commit d59af7737204d7f065ab0d1995569577cb643160 Author: Ilari Liusvaara Date: Fri May 3 17:47:19 2013 +0300 Import of bsnes v084 sources diff --git a/Makefile b/Makefile new file mode 100755 index 00000000..ec15feae --- /dev/null +++ b/Makefile @@ -0,0 +1,82 @@ +include nall/Makefile + +nes := nes +snes := snes +gameboy := gameboy +profile := accuracy +ui := ui + +# options += console +# options += debugger + +# compiler +c := $(compiler) -std=gnu99 +cpp := $(subst cc,++,$(compiler)) -std=gnu++0x +flags := -O3 -fomit-frame-pointer -I. +link := +objects := libco + +# profile-guided optimization mode +# pgo := instrument +# pgo := optimize + +ifeq ($(pgo),instrument) + flags += -fprofile-generate + link += -lgcov +else ifeq ($(pgo),optimize) + flags += -fprofile-use +endif + +# platform +ifeq ($(platform),x) + # tree vectorization causes code generation errors with Linux/GCC 4.6.1 + flags += -fno-tree-vectorize + link += -s -ldl -lX11 -lXext +else ifeq ($(platform),osx) +else ifeq ($(platform),win) + link += $(if $(findstring console,$(options)),-mconsole,-mwindows) + link += -mthreads -s -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 + link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc +else + unknown_platform: help; +endif + +flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o) + +# implicit rules +compile = \ + $(strip \ + $(if $(filter %.c,$<), \ + $(c) $(flags) $1 -c $< -o $@, \ + $(if $(filter %.cpp,$<), \ + $(cpp) $(flags) $1 -c $< -o $@ \ + ) \ + ) \ + ) + +%.o: $<; $(call compile) + +all: build; + +obj/libco.o: libco/libco.c libco/* + +include $(ui)/Makefile + +# targets +clean: + -@$(call delete,obj/*.o) + -@$(call delete,obj/*.a) + -@$(call delete,obj/*.so) + -@$(call delete,obj/*.dylib) + -@$(call delete,obj/*.dll) + -@$(call delete,*.res) + -@$(call delete,*.pgd) + -@$(call delete,*.pgc) + -@$(call delete,*.ilk) + -@$(call delete,*.pdb) + -@$(call delete,*.manifest) + +archive-all: + tar -cjf bsnes.tar.bz2 data gameboy libco nall nes obj out phoenix ruby snes ui ui-libsnes Makefile cc.bat clean.bat sync.sh + +help:; diff --git a/cc.bat b/cc.bat new file mode 100755 index 00000000..f49d74d3 --- /dev/null +++ b/cc.bat @@ -0,0 +1,2 @@ +@mingw32-make -j 8 +@pause diff --git a/clean.bat b/clean.bat new file mode 100755 index 00000000..d4c3d600 --- /dev/null +++ b/clean.bat @@ -0,0 +1 @@ +@mingw32-make clean diff --git a/data/bsnes.Manifest b/data/bsnes.Manifest new file mode 100755 index 00000000..e415f87a --- /dev/null +++ b/data/bsnes.Manifest @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/data/bsnes.desktop b/data/bsnes.desktop new file mode 100755 index 00000000..d527e973 --- /dev/null +++ b/data/bsnes.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=bsnes +Comment=SNES emulator +Exec=bsnes +Icon=bsnes +Terminal=false +Type=Application +Categories=Game;Emulator; diff --git a/data/bsnes.ico b/data/bsnes.ico new file mode 100755 index 00000000..54acded4 Binary files /dev/null and b/data/bsnes.ico differ diff --git a/data/bsnes.png b/data/bsnes.png new file mode 100755 index 00000000..02986ba8 Binary files /dev/null and b/data/bsnes.png differ diff --git a/data/cheats.bml b/data/cheats.bml new file mode 100755 index 00000000..b4b8cd32 --- /dev/null +++ b/data/cheats.bml @@ -0,0 +1,79635 @@ +cartridge sha256:e868400409c70876b98dad2cca87b8e9ee31877b0cccbbd8405be5c54922722a + title:1942 (Japan, USA) + cheat + description:Don't die when touched + code:OLZNEE + cheat + description:Most enemies die instantly + code:PAEIXKNY + cheat + description:Infinite lives - 1P game + code:SZXLKEVK + cheat + description:Infinite rolls + code:SZESPUVK + cheat + description:Hit anywhere + code:ALKUTGEL+SXULIKSO+SZELGKSO+SZKULGAX + cheat + description:Rapid fire + code:AEUSGZAP + cheat + description:After continue P1 has 6 lives - 2P game + code:IAKUUAZA + cheat + description:After continue P1 has 9 lives - 2P game + code:AAKUUAZE + cheat + description:P2 has 6 lives - 2P game + code:IASUOAZA + cheat + description:P2 has 9 lives - 2P game + code:AASUOAZE + cheat + description:Start with 9 rolls - both players + code:PASIOALE + cheat + description:Start with 6 lives - 1P game + code:IESUTYZA + cheat + description:Start with 9 lives - 1P game + code:AESUTYZE + cheat + description:Invincibility + code:048E:88 + cheat + description:Infinite rolls (alt) + code:0436:03 + cheat + description:Infinite lives + code:0432:02 + +cartridge sha256:9f54aafa367247b99c344ba9a0c58ad8fa8aceeeae1c304b8fefc9985c3c118c + title:1943 - The Battle of Midway (USA) + cheat + description:Infinite energy + code:OUNLAZGA + cheat + description:Infinite energy (alt) + code:SXVLZXSE+VVOULXVK + cheat + description:Infinite power-ups + code:SUTXGN + cheat + description:Infinite weapon upgrade time + code:SGOUZUVK + cheat + description:Don't instantly die from touching boss planes + code:NSKIELGA + cheat + description:Always shoot power shots + code:LEEPXLAE + cheat + description:Hit anywhere + code:AENSKLAP+GZESEGEL+SLSKOEOO+SXOINUOO+SXXGVEOO+SZKTSXOO+SZVGSVOO + cheat + description:10 power points + code:ZESNLLLE + cheat + description:20 power points + code:GOSNLLLA + cheat + description:30 power points + code:TOSNLLLE + cheat + description:Start on mission 5 + code:AEVYZLAE + cheat + description:Start on mission 10 + code:ZOVYZLAA + cheat + description:Start on mission 15 + code:GOVYZLAE + cheat + description:Start on mission 20 + code:TXVYZLAA + cheat + description:Invincibility + code:040E:60 + cheat + description:Infinite power points + code:0347:01 + cheat + description:Infinite energy (alt 2) + code:0410:09 + +cartridge sha256:cd8d9859f334901aca717e08be03dab077766927c87a2becda22982b9234d532 + title:1945 [p1] + cheat + description:Invincibility + code:SXOOAZAX+SXVOPGAX + cheat + description:Infinite Bombs + code:SXUAYLAX + +cartridge sha256:c457644ccfb93f8978326e728931800283821e531edc409fca9c0167495319c4 + title:3-D WorldRunner (USA) + cheat + description:Invincibility + code:ATPXIG + cheat + description:Infinite lives + code:AEUOLTPA + cheat + description:Infinite time + code:SXUPZGVG + cheat + description:Slow down timer + code:NNXOYGEK + cheat + description:Speed up timer + code:AVXOYGEG + cheat + description:Start with and keep laser missiles + code:AEUOVIGA + cheat + description:Autofire + code:OXUONISX + cheat + description:Start with 1 life + code:PEUPPTLA+PLVOLTLL + cheat + description:Start with 6 lives + code:TEUPPTLA+TLVOLTLL + cheat + description:Start with 9 lives + code:PEUPPTLE+PLVOLTLU + cheat + description:Start on world 2 + code:XZEAUOOZ+PAEAKPAA+VAEASPSA + cheat + description:Start on world 3 + code:XZEAUOOZ+ZAEAKPAA+VAEASPSA + cheat + description:Start on world 4 + code:XZEAUOOZ+LAEAKPAA+VAEASPSA + cheat + description:Start on world 5 + code:XZEAUOOZ+GAEAKPAA+VAEASPSA + cheat + description:Start on world 6 + code:XZEAUOOZ+IAEAKPAA+VAEASPSA + cheat + description:Start on world 7 + code:XZEAUOOZ+TAEAKPAA+VAEASPSA + cheat + description:No enemies or pitfalls + code:003A:05 + +cartridge sha256:df696ce2af90b18ca2b57468bdc525afce371bb1868152eb2cbbe1d62252f617 + title:720 Degrees (USA) + cheat + description:Infinite continues + code:SZUYASVK + cheat + description:9 continues + code:PEXKLZLE + cheat + description:6 continues + code:TEXKLZLA + cheat + description:No continues instead of 2 + code:PEXKLZLA + cheat + description:Start with all equipment + code:GEKKYZAA + cheat + description:Start with half equipment + code:ZEKKYZAA + cheat + description:Start on level 2 + code:XVXGGXSX+OXXGIXTE+ZEXGTZZA + cheat + description:Start on level 3 + code:XVXGGXSX+OXXGIXTE+LEXGTZZA + cheat + description:Start on level 4 + code:XVXGGXSX+OXXGIXTE+GEXGTZZA + cheat + description:Infinite time + code:0572:19 + cheat + description:Infinite time (one's digit) in half-pipe + code:0573:09 + cheat + description:Infinite time (ten's digit) in half-pipe + code:0574:09 + +cartridge sha256:3493f7621d964af7a56c407718ef1d056c6c46d4e4c6b3c48364d58a1b97a06a + title:8 Eyes (USA) + cheat + description:Invincibility - Orin + code:EIUUSLEY + cheat + description:Invincibility - Cutrus + code:EINGVPEY + cheat + description:Infinite health - Orin + code:SXOUSUSE + cheat + description:Infinite health - Cutrus + code:SXNGNOSE + cheat + description:Most attacks won't damage Orin + code:GXOUSUSE + cheat + description:Most attacks won't damage Cutrus + code:GXNGNOSE + cheat + description:Start with more health - Orin + code:AGVXGXYZ + cheat + description:Start with more health - Cutrus + code:AGVXIXYZ + cheat + description:Infinite ammo + code:SXSLKVSE + cheat + description:Start with all weapons + code:SAOVUTVA + cheat + description:Start with max ammo + code:YGVXTXYX + cheat + description:Start with some item power + code:YZVXTZAE + cheat + description:Never lose item power once gained + code:GXSLKVSE + cheat + description:Start with Dagger + code:VTOVNTVA + cheat + description:Invincibility - Orin (blinking) + code:030E:10 + cheat + description:Invincibility - Cutrus (blinking) + code:032E:10 + cheat + description:Infinite health - Orin (alt) + code:0594:4F + cheat + description:Infinite health - Cutrus (alt) + code:0595:4F + cheat + description:Infinite item power + code:0596:4F + cheat + description:Bosses have no invulnerability time + code:034E:00 + cheat + description:Bosses defeated instantly + code:034F:00 + cheat + description:Doors never close once opened + code:009D:FA + cheat + description:Have Boomerang + code:007F:02 + cheat + description:Have Ice Ball + code:007F:04 + cheat + description:Have Power Ball + code:007F:08 + cheat + description:Have Dagger, Boomerang, Molotov Cocktail, Hand Gun + code:007F:33 + +cartridge sha256:c4d4ff0bd283656c63d9a30dfc7dc6d2956744730a3641ba2c8f9f8e7204d9a1 + title:Abadox - The Deadly Inner War (USA) + cheat + description:Invincibility + code:AVVTXYSZ + cheat + description:Invincible against walls + code:EIUISSOZ+PYUIVIZA + cheat + description:Infinite lives + code:PEIGPN + cheat + description:Infinite lives (alt) + code:VVIGAY + cheat + description:Invincibility (alt) + code:0086:00+008A:00 + cheat + description:Speed up level 1 + code:008B:01 + cheat + description:Speed up level 2 + code:008B:02 + cheat + description:Speed up level 3 + code:008B:03 + +cartridge sha256:6da6c8ac123df0f51e6f1b2ba79cb067d3352262532604ab08cf5dd587e84006 + title:Action in New York (Europe) + cheat + description:Invincibility + code:AVISVG + +cartridge sha256:005c48a5984e3b75e069ef78d736266b12f7f6b102d88d90172ba9ae480b378b + title:Addams Family, The (USA) + cheat + description:Invincibility + code:SXPATK + cheat + description:Infinite life + code:GXKKZSVK + cheat + description:Infinite lives + code:GXSVAUVK + cheat + description:Infinite Things + code:GXEVLVVK + cheat + description:Start with 1 life - 1st game only + code:PEVGGALA + cheat + description:Start with 6 lives - 1st game only + code:TEVGGALA + cheat + description:Start with 9 lives - 1st game only + code:PEVGGALE + cheat + description:Start in the tree + code:PEKGTAAA + cheat + description:Start in the crypt + code:ZEKGTAAA + cheat + description:Start in the hallway + code:LEKGTAAA + cheat + description:Start in Fester's room + code:AEKGTAAE + cheat + description:Start in Pugsly's room + code:PEKGTAAE + cheat + description:Start in the toy room + code:ZEKGTAAE + cheat + description:Start in Wednesday's room + code:LEKGTAAE + cheat + description:Start in the attic + code:GEKGTAAE + cheat + description:Start in a secret room + code:YEKGTAAE + cheat + description:Start in a secret room + code:AOKGTAAA + cheat + description:Start in a secret room + code:POKGTAAA + cheat + description:Start in the bone room + code:IOKGTAAE + cheat + description:Start in the freezer + code:PXKGTAAA + cheat + description:Start in the furnace + code:ZXKGTAAA + cheat + description:Start in Gomez's room + code:AXKGTAAA + +cartridge sha256:b3e09c94e33e0293672c1405c60fc69b2ab1564c8a4ee988e3ab6ada51484eea + title:Addams Family, The - Pugsley's Scavenger Hunt (USA) + cheat + description:Invincibility + code:ATGKAG + cheat + description:Infinite health + code:SZGKAK + cheat + description:Infinite health (alt) + code:AAKGYGPA + cheat + description:Infinite lives + code:SXUGZKVK + cheat + description:Infinite lives (alt) + code:SULGZK + cheat + description:Always able to fly + code:AASVUGIL + cheat + description:Mega-jump + code:AOVTETAO + cheat + description:Start with 1 life + code:PEVKZTIA + cheat + description:Start with 9 lives + code:PEVKZTIE + cheat + description:Start with 1 heart + code:PENKZTZA + cheat + description:Start with 4 hearts + code:GENKZTZA + cheat + description:Infinite health (alt 2) + code:0435:02 + cheat + description:Infinite lives (alt 2) + code:0438:09 + +cartridge sha256:22e92af92aed2d8d7bddb60732963642788b3ea9341592ce2c66a542a3d7ce7d + title:Advanced Dungeons & Dragons - DragonStrike (USA) + cheat + description:Invincibility + code:ATGGNY + cheat + description:Infinite health + code:SZGGNN + cheat + description:Infinite health (alt) + code:OTKGSYSV + cheat + description:Weapon power doesn't weaken with health + code:GZKKNNSE + cheat + description:Gold dragon has excellent armor class + code:TTXGIALT + cheat + description:Gold dragon flies faster + code:YGXKAAPG + cheat + description:Silver dragon flies faster + code:ATXGYAGV + cheat + description:Bronze dragon flies faster + code:YIXGTALI + cheat + description:Start wtih less health - bronze dragon + code:GPKZGEAZ + cheat + description:Start wtih more health - bronze dragon + code:AIKZGEAZ + cheat + description:Start wtih less health - silver dragon + code:TPKZIEGU + cheat + description:Start wtih more health - silver dragon + code:AIKZIEGL + cheat + description:Start wtih less health - gold dragon + code:ZZKZTAAS + cheat + description:Start wtih more health - gold dragon + code:ITKZTAAI + +cartridge sha256:df2609c80e818bb95983b30a3ac1435ea2332ac83e29fde469f397e1d5a2db93 + title:Advanced Dungeons & Dragons - Heroes of the Lance (USA) + cheat + description:Infinite HP for party in most battles + code:SUOAZGSP + +cartridge sha256:60061c0042741f7c1e53ad8f738c27ffd9057310ff5d556662b3667e5700e751 + title:Advanced Dungeons & Dragons - Hillsfar (USA) + cheat + description:Infinite Knock Rings + code:SXKUTSVK+AEKUISAI + cheat + description:Faster timer when lock-picking + code:AOULILAZ + cheat + description:Slower timer when lock-picking + code:ASULILAZ + cheat + description:Very slow timer when lock-picking + code:ENULILAZ + cheat + description:Start with 50% less gold on a character that you create + code:IEVANKZA + cheat + description:Start with 50% more gold on a character that you create + code:YEVANKZE + cheat + description:Start with 100% more gold on a character that you create + code:GOVANKZA + +cartridge sha256:38e5253131d264395a302d0910316f94bec00f60db616caa7a53806f08c5b5f9 + title:Advanced Dungeons & Dragons - Pool of Radiance (USA) + cheat + description:Create super characters + code:SOLAUN + cheat + description:Girdle Of Giant strength (must be used to be effective) + code:XGLAUN+GGLAUP + cheat + description:Extra EXP points + code:TLGAXL + cheat + description:One hit ends battle with no gold or EXP + code:AXLALN + +cartridge sha256:5ee479ef04d80366a75dd144cbeb47d0347ee82025d1b65dd358e1f6498c9a39 + title:Adventure Island II (USA) + cheat + description:Invincibility + code:ENUSOTEI + cheat + description:Invincibility (alt) + code:AVSSVVOZ + cheat + description:Infinite health + code:VTUIGEVK + cheat + description:Infinite health (alt) + code:SZUIGEVK + cheat + description:Infinite health against hitting objects + code:AAKSEYZA + cheat + description:Infinite Axes + code:PITXUZ + cheat + description:Infinite Axes plus get an extra Red Camptosaurus + code:NULLEX + cheat + description:Infinite lives + code:SXNLOKVK + cheat + description:Hit anywhere + code:ESKIEIEL+OLEIKVOO+OLXIOVOO+OUEISVOO+SXUSSIAX+TEUSNSNY+ZEUSVIUG + cheat + description:Never lose Dinosaur + code:SXXLEGSA+SZESEYSA+SZVSVYSA + cheat + description:Get fruits from anywhere + code:AAKXINIG + cheat + description:Multi-jump (hold jump to float) + code:KOOUZOYS+UXXLPOYI + cheat + description:Hold jump to float + code:VNXUIZZE + cheat + description:Reversible skateboard + code:AENZTPAZ + cheat + description:Faster running + code:ALKXAAAZ + cheat + description:Higher jump + code:SXSUAOSU+GEXULGPA + cheat + description:Start with 2 lives + code:PEXVAALA + cheat + description:Start with 7 lives + code:TEXVAALA + cheat + description:Start with 10 lives + code:PEXVAALE + +cartridge sha256:e8dc8c0441c54d09a1cfe0c112a3137bb6d709989b23e6528f8e30360e1ad910 + title:Adventure Island 3 (USA) + cheat + description:Invincibility + code:AEVXKGPA + cheat + description:Infinite health + code:SXOYOSVK + cheat + description:Infinite vitality + code:SKOYOSVK + cheat + description:Infinite lives + code:SXNLISSE + cheat + description:Hit anywhere + code:AAEZKLLA+AVSXKSOL+OUEXNSOO+OUEXSVOO + cheat + description:Hold jump to float + code:EYSXZAEI + cheat + description:Don't die when hitting spikes + code:AEUZNTPA + cheat + description:Don't lose pet when hitting spikes + code:SAKZSYVT + cheat + description:Mega-jumping Master Higgins + code:SUEZEXLN + cheat + description:Gain 99 lives after gaining 100 fruit + code:AAKXGTZA + cheat + description:Keep items after dying - after 1st stage + code:GXUUGOSO + cheat + description:Start a new game to view the ending + code:AAEZYIGA+LAEZLSZA + cheat + description:Start with 2 lives + code:PESZAALA + cheat + description:Start with 7 lives + code:TESZAALA + cheat + description:Start with 9 lives + code:PESZAALE + cheat + description:Start with 2 Red Taylors + code:VTVZZESE + cheat + description:Start with 2 Blue Taylors + code:VTVZIESE + cheat + description:Start with 2 Classies + code:VTVXAESE + cheat + description:Start with 2 Don-Dons + code:VTVXLESE + cheat + description:Start with 2 Poleys + code:VTVXTESE + cheat + description:Start with 2 Boomerangs + code:VTNZPESE + cheat + description:Start with 2 Axes + code:VTNZGESE + cheat + description:Start with 2 invincibility crystals + code:VTNZYESE + +cartridge sha256:185e4adb2cbcb71ebf0fd3f6af767f2215f93916cd2ccf932ce5864d3953239a + title:Adventures in the Magic Kingdom (USA) + cheat + description:Invincibility + code:ATPNTI + cheat + description:Infinite health + code:AVXNXPVG + cheat + description:Infinite time + code:ATXYKZEL + cheat + description:Infinite candles + code:SZSTGVVK + cheat + description:Infinite lives + code:SXKYUOVK + cheat + description:Almost infinite health in attractions + code:SXXNXPVG + cheat + description:All items for free + code:GXELLXSN+AAXUAXGY + cheat + description:Mega-jump + code:EYKVNKXN + cheat + description:'Life' costs less + code:LAKUTGTA + cheat + description:'Life' costs more + code:GAKUTGTE + cheat + description:'Freeze' costs less + code:GAKUYKAA + cheat + description:'Freeze' costs more + code:YAKUYKAE + cheat + description:'Invincible' costs less + code:IASLAKZA + cheat + description:'Invincible' costs more + code:GPSLAKZA + cheat + description:'Life Up' costs less + code:TASLPKGA + cheat + description:'Life Up' costs more + code:APSLPKGE + cheat + description:Never lose a life in 'attractions' + code:SXKYUOVK + cheat + description:More 'Freeze' time + code:NYKULZKU + cheat + description:Less 'Freeze' time + code:AGKULZKL + cheat + description:More 'Invincible' time + code:EGSUYXGL + cheat + description:Start with less health in attractions + code:PAVAZPLA + cheat + description:Start with more health in attractions + code:IAVAZPLA + cheat + description:Start with even more health in attractions + code:PAVAZPLE + cheat + description:Start with 1 life + code:PEVEIALA + cheat + description:Start with 6 lives + code:TEVEIALA + cheat + description:Start with 9 lives + code:PEVEIALE + +cartridge sha256:0e862077f390348b8e109caa8189ff5ecdf3fac53eefc204369fae880e077d19 + title:Adventures of Bayou Billy, The (USA) + cheat + description:Infinite health + code:PEKVIZYA+SXOOUKVK + cheat + description:Infinite lives + code:GZOVLLVG + cheat + description:Always have pistol + code:EZNATKKZ+XTNEAGYE+PANAYGOG + cheat + description:Always have knife + code:EZNATKKZ+XTNEAGYE+ZANAYGOG + cheat + description:Always have ugly stick + code:EZNATKKZ+XTNEAGYE+LANAYGOG + cheat + description:Always have whip + code:EZNATKKZ+XTNEAGYE+IANAYGOG + cheat + description:Start a new game to view the ending (game A or B) + code:IEOVAYGA + cheat + description:Start with 1 life + code:AAETAGZA + cheat + description:Start with 6 lives + code:IAETAGZA + cheat + description:Start with 9 lives + code:AAETAGZE + cheat + description:Start on level 2 + code:PAEVZGAA+UYEVGKPU+AAEVAGGA + cheat + description:Start on level 3 + code:ZAEVZGAA+UYEVGKPU+AAEVAGGA + cheat + description:Start on level 4 + code:LAEVZGAA+UYEVGKPU+AAEVAGGA + cheat + description:Start on level 5 + code:GAEVZGAA+UYEVGKPU+AAEVAGGA + cheat + description:Start on level 6 + code:IAEVZGAA+UYEVGKPU+AAEVAGGA + cheat + description:Start on level 7 + code:TAEVZGAA+UYEVGKPU+AAEVAGGA + cheat + description:Start on level 8 + code:YAEVZGAA+UYEVGKPU+AAEVAGGA + cheat + description:Infinite health (alt) + code:07C5:07 + cheat + description:One hit kills + code:0510:00+0511:00+0512:00+0513:00+0514:00 + cheat + description:Have the Gun + code:07C1:01 + cheat + description:have the Knife + code:07C1:02 + cheat + description:Have the Ugly Stick + code:07C1:03 + cheat + description:Have the Whip + code:07C1:05 + cheat + description:Infinite bullets + code:07C0:99 + +cartridge sha256:58d0f0e504b8450e7d2dfbe11948a244143bfe3065f7e78524633cce8ac73103 + title:Adventures of Dino Riki (USA) + cheat + description:Invincibility + code:ATLAEZ + cheat + description:Don't fall into the pits (you'll still lose any special ability you currently have) + code:AEKAOPZA + cheat + description:Once Macho, stay Macho + code:IEVASPIG + cheat + description:Start and stay as Macho-Riki + code:VKEAPISA + cheat + description:Start as Macho-Riki + code:VVEAPISA + cheat + description:Start with infinite lives + code:SZEETTVG + cheat + description:Start with 1 life + code:AESEPGZA + cheat + description:Start with 6 lives + code:IESEPGZA + cheat + description:Start with 9 lives + code:AESEPGZE + cheat + description:Start with infinite life hearts + code:SZUENZVG + cheat + description:Start with 4 life hearts + code:GESEIGZA + cheat + description:Start with 8 life hearts + code:AESEIGZE + cheat + description:Start on stage 2-1 + code:TKSAAGSA+ZEKEIGAA + cheat + description:Start on stage 3-1 + code:TKSAAGSA+GEKEIGAA + cheat + description:Start on stage 4-1 + code:TKSAAGSA+TEKEIGAA + cheat + description:Start on stage 4-2 + code:TKSAAGSA+AEKEIGAE + cheat + description:Start on stage 4-3 + code:TKSAAGSA+ZEKEIGAE + cheat + description:Start on stage 4-4 + code:TKSAAGSA+GEKEIGAE + +cartridge sha256:bb5859ced6b028934edddc734e3599f8dd7857b92838baf6a7d46df5dd151f6b + title:Adventures of Dr. Franken, The (USA) (Proto) + cheat + description:Infinite health + code:SXVVYTVG + +cartridge sha256:a0bc241936acf1993a300ab21c197a2647b6c072cfbb8e3f83424a9ab6655cc7 + title:Adventures of Gilligan's Island, The (USA) + cheat + description:Infinite time + code:SZENLZVG + cheat + description:Infinite rope + code:SZSUAUVK + cheat + description:Infinite supply of food + code:SZXUIUVK + cheat + description:Start with 9 units of food + code:PAXIUIZE + cheat + description:Start with 1 unit of food + code:PAXIUIZA + cheat + description:More time for Episode 1 + code:LANNLXPE + cheat + description:More time for Episode 2 + code:IANNGXLE + cheat + description:More time for Episode 3 + code:GPNNIZLP + cheat + description:Start with 9 ropes + code:PAXSEIZE + cheat + description:Start with 1 rope + code:PAXSEIZA + cheat + description:Start on Episode 2 + code:PAVSXGAA+GZVSUGSA + cheat + description:Start on Episode 3 + code:ZAVSXGAA+GZVSUGSA + +cartridge sha256:c5e47c0479f500b86995fc8d09e132f5ba3f54cfd9a2a601ea3848bb60871a20 + title:Adventures of Lolo (USA) + cheat + description:Invincibility + code:ATOKOAVT+AVXUPZVT + cheat + description:Infinite lives + code:SXOPSPVG + cheat + description:Always have shot ability + code:TASLIEUY + cheat + description:1 life for Lolo + code:PEKPOAIA + cheat + description:9 lives for Lolo + code:PEKPOAIE + +cartridge sha256:12d3119e25f7b40a7ccc546f5d92edaad86fb0083facf6dd61db512bac45f99d + title:Adventures of Lolo 2 (USA) + cheat + description:Invincibility + code:AVUXXLVT + cheat + description:Infinite lives + code:GZXPVLVG + cheat + description:Always have shot ability + code:GENXEEUY + cheat + description:Never lose magic shots + code:GXNXUAVG + cheat + description:Start with 1 life + code:PESPXPIA + cheat + description:Start with 10 lives + code:ZESPXPIE + cheat + description:Start with 15 lives + code:YESPXPIE + cheat + description:Start with 2 magic shots + code:ZAEPSZAA + cheat + description:Start with 4 magic shots + code:GAEPSZAA + cheat + description:Start on world 5 + code:GEUPKPAA + cheat + description:Start on world 10 + code:PEUPKPAE + cheat + description:Start on world 15 + code:TEUPKPAE + cheat + description:Start on world 20 + code:LOUPKPAA + cheat + description:Start on world 25 + code:AOUPKPAE + cheat + description:Start on world 30 + code:IOUPKPAE + +cartridge sha256:24f7bb802a0ddce0648ea9f156db42b3eaf4cc6598ce852ffac9f849bf92abee + title:Adventures of Lolo 3 (USA) + cheat + description:Invincibility + code:AVNPTTVT+ATXAVIVT + cheat + description:Always have shot ability + code:ZEOAKXUY + cheat + description:Infinite shots for each room on pick-up + code:SXOASZVG + +cartridge sha256:322d6be47ed539c3dd3c1c92398e9842c3922d7c13914b9c72752ddec377145c + title:Adventures of Rad Gravity, The (USA) + cheat + description:Infinite health + code:SUTTXU + +cartridge sha256:03db3d003eaa91e1434093ea259a82b9f2d5ed5b02404f9feba05819f69f81c4 + title:Adventures of Rocky and Bullwinkle and Friends, The (USA) + cheat + description:Infinite health + code:SXOESKSE + cheat + description:Infinite lives + code:SZNEUKVK + cheat + description:Infinite Bombs + code:SKKAPVVK + cheat + description:Rocky loses no health when flying when you have full health + code:TAVEYGYA + cheat + description:Rocky loses more health when flying when you have full health + code:TAVEAGZA + cheat + description:Bullwinkle loses no health when headbutting + code:AANAIGPA + cheat + description:Bullwinkle loses more health when headbutting + code:AANAPGGE + cheat + description:Start with 2 lives + code:PAOEZAGA + cheat + description:Start with 30 Bombs + code:TPOEYEZE + cheat + description:Start with no Bombs + code:AAOEYEZA+AEEIGXZA + +cartridge sha256:227e8a900206d0f8c67b7cb09eaee25f181085623b42bd9694dc30986d955f27 + title:Adventures of Tom Sawyer (USA) + cheat + description:Infinite Toms + code:VZOGGPVG + cheat + description:Only 5 T's lost from skulls + code:IAXGTSZA + cheat + description:Start with 1 Tom - P1 + code:PEUZIALA + cheat + description:Start with 1 Tom - P2 + code:PANXLLLA + cheat + description:Start with 6 Toms - P1 + code:TEUZIALA + cheat + description:Start with 6 Toms - P2 + code:TANXLLLA + cheat + description:Start with 9 Toms - P1 + code:PEUZIALE + cheat + description:Start with 9 Toms - P2 + code:PANXLLLE + cheat + description:Start at the river - P1 + code:OGSZZSVU + cheat + description:Start in the forest - P1 + code:KISZZSVL + cheat + description:Start in the house - P1 + code:NISZZSVU + cheat + description:Start in the sky - P1 + code:XTSZZSVU + cheat + description:Start in the cave - P1 + code:SYSZZSVL + cheat + description:Start at the river - P2 + code:ZEEZALPA+AEEXZLLE + cheat + description:Start in the forest - P2 + code:LEEZALPA+IEEXZLLE + cheat + description:Start in the house - P2 + code:GEEZALPA+ZOEXZLLA + cheat + description:Start in the sky - P2 + code:IEEZALPA+YOEXZLLA + cheat + description:Start in the cave - P2 + code:TEEZALPA+GOEXZLLE + +cartridge sha256:69300586af39342fccc249134f6f44ebbd0fce7c1e5b93151cff63bb35072add + title:After Burner (USA) (Unl) + cheat + description:Invincibility + code:SZKOLZSA + cheat + description:Infinite lives + code:SKXVPZVG + cheat + description:Infinite missiles + code:SKNAXZVG + +cartridge sha256:4fb12ad1c791c7ee8d5ec824eff871d71b43b92c4e93b45ed0b60f022459b917 + title:After Burner (Japan) + cheat + description:Infinite lives + code:SXNTPPVG + +cartridge sha256:1b5857f9fd57d6f50d8d1e57db67203155fb2974ae426deac3398efef1dbf042 + title:Aigina no Yogen - Balubalouk no Densetsu Yori (Japan) + cheat + description:Invincibility + code:SXIPPS + cheat + description:Infinite lives + code:SLLOPK + +cartridge sha256:e10ff4cfeaf0c16a71d7fffbf79ad3260c119431db6fad603d07ec971746849a + title:Airball (Unknown) (Proto1) + cheat + description:Can use float at any difficulty level + code:AEEGAIAP + +cartridge sha256:6d0215929f2dfeeecdeee4dd50b8aec07f279a8ab8df1dc4e877bbcad3db0d37 + title:Air Fortress (USA) + cheat + description:Invincibility + code:ESSXAYEY+ENSXIYEI + cheat + description:Infinite energy + code:SXKKNSSE+SZEGOVSE + cheat + description:Don't take damage inside fortress + code:GXKKSIST+GXNKNIST + cheat + description:Infinite lives + code:SGUPKGVG + cheat + description:Infinite lives outside fortress + code:SZUPKGVG + cheat + description:Start with 1 life + code:PAVPKZLA + cheat + description:Start with 6 lives + code:TAVPKZLA + cheat + description:Start with 9 lives + code:PAVPKZLE + cheat + description:Infinite Beam Bullets + code:AAKPSTPA + cheat + description:Double Bombs on pick-up + code:APKZNGIA + cheat + description:Extra energy on pick-up + code:YYNXUZGV+YNEZEZGV + cheat + description:Start on level 2 + code:XZSOXXPZ+PASOUZYA+VASOKZSA + cheat + description:Start on level 3 + code:XZSOXXPZ+ZASOUZYA+VASOKZSA + cheat + description:Start on level 4 + code:XZSOXXPZ+LASOUZYA+VASOKZSA + cheat + description:Start on level 5 + code:XZSOXXPZ+GASOUZYA+VASOKZSA + cheat + description:Start on level 6 + code:XZSOXXPZ+IASOUZYA+VASOKZSA + cheat + description:Start on level 7 + code:XZSOXXPZ+TASOUZYA+VASOKZSA + +cartridge sha256:b82c1234165cd725d8e7f3e51926bceb834744eb49ad915bd3ea8b76fa465eb1 + title:Airwolf (USA) + cheat + description:Infinite health + code:SLTXSN + cheat + description:Infinite lives + code:SUTAPX + cheat + description:Start with 1 life + code:PAUGVILA + cheat + description:Start with 6 lives + code:TAUGVILA + cheat + description:Start with 9 lives + code:PAUGVILE + cheat + description:Start at last mission reached + code:PVXKKKLI + cheat + description:Start with 30 missiles + code:TPVAPXYE + cheat + description:Start with 45 missiles + code:IZVAPXYE + cheat + description:Start with infinite missiles + code:GXSZAPVG + cheat + description:Sets missiles to 5 when you refuel + code:IEVAISYA + cheat + description:Sets missiles to 30 when you refuel + code:TOVAISYE + cheat + description:Infinite health (alt) + code:00B9:00 + cheat + description:Infinite lives (alt) + code:036C:02 + +cartridge sha256:60b1aebdc0a19afc5d3e7dc4f09d8a968580e007197461a8a142656702c27f0d + title:Akumajou Dracula (Japan) + cheat + description:Infinite health + code:SXKTAYSE + cheat + description:Infinite lives + code:OZOGZLVK + cheat + description:Infinite time + code:SXUZGAAX + cheat + description:Clock doesn't use hearts + code:KXXSXZKA + cheat + description:Weapons don't use hearts + code:KXVISZKA + cheat + description:Can't add hearts + code:KXVVPYSA + cheat + description:Keep weapon after losing a life + code:GZUKLUSE + cheat + description:Start with rapid-fire shots + code:AEELATPA + cheat + description:Start with 80 hearts + code:ASEGUPIA + cheat + description:Start with 99 hearts + code:LVEGUPIA + +cartridge sha256:c70f0f5d4054ce7c4850259879c9823add73ccc234ddcf96d95681bb78bd2c58 + title:Akumajou Densetsu (Japan) + cheat + description:Infinite life + code:SAXANGSZ + cheat + description:Infinite hearts + code:AANEKLPA + cheat + description:Infinite time + code:IEOESPLA + cheat + description:Infinite lives + code:SZNEKPSE + cheat + description:Multi-jump + code:OZVPEAES+SASOSESX+SAVPXESX+SZUOEASA+SZSOEAGA+ZASOXEAE+AVSANLAP+ASSOGYTS+ASSOGLTS+AZSOOEOK+EIVPUAIV+EPSOUAEL+IAVOEEAA+IAVPOEGA+IAVPVATZ + +cartridge sha256:ff5b96853cf67171918aad5157661dc223e0002e0373e2580cee2e207bb0a682 + title:Akumajou Special - Boku Dracula-kun (Japan) + cheat + description:Invincibility + code:AVASEI + cheat + description:Infinite health + code:SXESEIVG + cheat + description:Infinite lives + code:SXXSVGVG + +cartridge sha256:722096b8929442310bc268f9cfea10b26cff8a7e900197b54c73b4a8603b5d96 + title:Aladdin (Europe) + cheat + description:Invincibility + code:ESNKNGEY+ESEYUPEY + cheat + description:Infinite energy + code:SZEUSZSA + cheat + description:Infinite lives + code:SXKGYXSE + cheat + description:Infinite Apples + code:SXEKKESE + +cartridge sha256:4b088e1e78981308da68883cf8292337ff8d899bf82a78d17e7a7af2745846e7 + title:Alfred Chicken (USA) + cheat + description:Invincibility + code:SXZNIG + cheat + description:Infinite time (alt) + code:AVGLXA + cheat + description:Infinite lives + code:EVKNKAPA + cheat + description:Infinite lives (alt) + code:SXGNXE + cheat + description:Infinite time + code:AVULEESZ + cheat + description:255 points for each present collected + code:NNXYKPZU + cheat + description:108 points for each present collected + code:GVXYKPZL + cheat + description:Only need 1 diamond for an extra life + code:PAKLTPTA + cheat + description:3 balloons needed to complete a level + code:OZXKXZOU+LAXKUZPI + cheat + description:2 balloons needed to complete a level + code:OZXKXZOU+ZAXKUZPI + cheat + description:1 balloon needed to complete a level + code:OZXKXZOU+PAXKUZPI + cheat + description:Start with 1 life + code:AASGITZA + cheat + description:Start with 2 lives + code:PASGITZA + cheat + description:Always spring-jump + code:DD68:90 + +cartridge sha256:d73a9a1fae7396754c19eecd6aa9e44d02c230df8efed0bafd86aa1cb0dd2a23 + title:Alien 3 (USA) + cheat + description:Invincibility + code:SXOPNKVK+YEKVUPGV+YESIGIGV + cheat + description:Infinite health + code:SXUYUXSE + cheat + description:Infinite time + code:SUEUTXSO + cheat + description:Infinite lives + code:SZKVZXVK + cheat + description:Infinite gun heat + code:SXOSNKVT + cheat + description:Super-jump + code:IPUZTALA+IPUXPALA + cheat + description:Invincible against long falls + code:AASGKNYA + cheat + description:Always have Radar + code:NNKVNPAE + cheat + description:Infinite Radar + code:SZVXVXVK + cheat + description:Infinite ammo for Machine gun + code:SXXSNKVK + cheat + description:Infinite ammo for Grenade Launcher + code:SZVSSKVK + cheat + description:Infinite ammo for Grenade Launcher 2 + code:SZKLVSVK + cheat + description:Infinite ammo for Flame Thrower + code:SZEIUOVK + cheat + description:Level skip (pause and press any key (except left) + code:TUVUYLZG + cheat + description:Invincibility (alt) + code:03C8:4A + cheat + description:Infinite health (alt) + code:074A:12 + cheat + description:Infinite time + code:0742:09+0743:09+0744:09 + cheat + description:Infinite weapon 1 + code:074B:3F + cheat + description:Infinite weapon 2 + code:074C:20 + cheat + description:Infinite weapon 3 + code:074E:1C + cheat + description:Infinite weapon 4 + code:074D:32 + cheat + description:Rescue all now + code:0747:00 + +cartridge sha256:cd1a9bc6c9e2181668fea96db14bc67fbbf9bf1572eef2bb074e5912a0dd54c9 + title:Alien Syndrome (Japan) + cheat + description:Infinite lives + code:OUYKKT + cheat + description:Infinite time + code:SUANPN + cheat + description:Don't lose life when touched + code:OLZEEP + +cartridge sha256:d676ef6f7aa3b042ae5a0c95a7f07fabb4c3a5fccb3767ae1950713e51189a47 + title:Alien Syndrome (USA) (Unl) + cheat + description:Infinite time + code:SZUNYXVK + cheat + description:Don't lose life when shot or touched + code:AEEKXONY + cheat + description:Don't lose life from falling down holes + code:AANGVXNY + cheat + description:Set timer to 440 + code:GUONPPLL + cheat + description:1 life after continue + code:PEXGGLGA + cheat + description:8 lives after continue + code:AEXGGLGE + cheat + description:Start with 1 life - both players + code:PAOGPIGA + cheat + description:Start with 8 lives - both players + code:AAOGPIGE + cheat + description:Start with Flame Thrower + code:PAVKGIAA + cheat + description:Start with Fireball + code:ZAVKGIAA + cheat + description:Start with Laser + code:LAVKGIAA + cheat + description:Start on round 2 + code:PENNELAP+KUNNXLAA+LENNULAZ + cheat + description:Start on round 3 + code:ZENNELAP+KUNNXLAA+LENNULAZ + cheat + description:Start on round 4 + code:LENNELAP+KUNNXLAA+LENNULAZ + cheat + description:Start on round 5 + code:GENNELAP+KUNNXLAA+LENNULAZ + cheat + description:Start on round 6 + code:IENNELAP+KUNNXLAA+LENNULAZ + cheat + description:Start on round 7 + code:TENNELAP+KUNNXLAA+LENNULAZ + +cartridge sha256:a762d0a90d16c84b5f2b014816b37675cf5115320be7e815effbb64d91b2014d + title:All Night Nippon Super Mario Brothers (Japan) (Promotion Card) + cheat + description:All blocks are starmen + code:SKGEOO + cheat + description:Invisible 1-up blocks are visible and all mushroom blocks are 1-ups + code:OKYEOP + cheat + description:Start on level 8-4 + code:YEUGZGAA+LEUKGGAA + +cartridge sha256:3addebdec132929ecad2a8612a4ba54ccc39b9ada2295692f836c6b48d015054 + title:Alpha Mission (USA) + cheat + description:Invincibility + code:OUXKZPOP + cheat + description:Infinite lives + code:SXSPYZVG + cheat + description:Keep power up after death + code:GZNAILSA + cheat + description:Keep energy after death + code:GZNAYLSA + cheat + description:Thunder uses 25% normal energy + code:GAEOUEAA + cheat + description:Triple energy gained on 'E' pick-up + code:TEXLPTZA + cheat + description:Less energy lost on 'Bad E' pick-ups + code:ZEULGTGA + cheat + description:Shield doesn't use energy + code:SZEGGASA + cheat + description:You can re-use weapon after selecting + code:IZNAEGSA + cheat + description:Start with all weapons available + code:NYKAYLLE + cheat + description:Start with 1 life + code:PASATLLA + cheat + description:Start with double lives + code:TASATLLA + cheat + description:Start with triple lives + code:PASATLLE + +cartridge sha256:a978de5d5f343eacb0a6f12427327ecbe9b2e9cf881569aec7b838bd44237d84 + title:Amagon (USA) + cheat + description:Invincibility + code:ESNIZLEY + cheat + description:Invincible against enemies + code:AVOXGOOZ + cheat + description:Invincible against bullets + code:ATXZPOOZ + cheat + description:Invincible against area boss + code:AVNZAOOZ + cheat + description:Infinite mega-power + code:GZSZIZSP + cheat + description:Infinite ammo + code:AAVYLTPA + cheat + description:Infinite ammo (alt) + code:SLVYGTSP + cheat + description:Gain 10 bullets on pick-up + code:PAVKUIZA + cheat + description:Gain 30 bullets on pick-up + code:LAVKUIZA + cheat + description:Start with no bullets + code:PEOVPZGA + cheat + description:Start with 600 bullets + code:YEOVPZGA + cheat + description:Start with infinite lives + code:AAXGNYPA + cheat + description:Start with 1 life + code:PEOVIZGA + cheat + description:Start with 8 lives + code:AEOVIZGE + +cartridge sha256:be12cff13a06e0b5de2dad4d431f7cf9a6aa73be45cdbd952dfd03a9d23571b6 + title:American Gladiators (USA) + cheat + description:Less joust time + code:GLUOZGLV + cheat + description:Stop joust timer + code:GZXXLUVK + cheat + description:Less cannonball time + code:GLOEGALV + cheat + description:Stop cannonball time + code:GZEPGOVK + cheat + description:Less wall time + code:GLKXXZLV + cheat + description:Stop wall timer + code:GXOXEXVS + cheat + description:More assault time + code:LTXATNIL + cheat + description:Less assault time + code:PZXATNIU + cheat + description:Stop assault timer + code:GZSAINVK + cheat + description:More power ball time - level 1 + code:LTSOZOIL + cheat + description:More power ball time - level 2 + code:LTSOLOAL + cheat + description:More power ball time - level 3 + code:LTSOGPLL + cheat + description:More power ball time - level 4 + code:LTSOIOTZ + cheat + description:Start with 1 life - P1 + code:PEXALTIA + cheat + description:Start with 8 lives - P1 + code:AEXALTIE + cheat + description:Start with 10 lives - P1 + code:ZEXALTIE + cheat + description:Start with 20 lives - P1 + code:GOXALTIA + cheat + description:Start with 1 life - P2 + code:PEVALTIA + cheat + description:Start with 8 lives - P2 + code:AEVALTIE + cheat + description:Start with 10 lives - P2 + code:ZEVALTIE + cheat + description:Start with 20 lives - P2 + code:GOVALTIA + cheat + description:Start on level 2 - P1 + code:PEXAPTAA + cheat + description:Start on level 3 - P1 + code:ZEXAPTAA + cheat + description:Start on level 4 - P1 + code:LEXAPTAA + cheat + description:Start on level 2 - P2 + code:PEVAPTAA + cheat + description:Start on level 3 - P2 + code:ZEVAPTAA + cheat + description:Start on level 4 - P2 + code:LEVAPTAA + +cartridge sha256:427876021e6c077479a1a1171e013f84ae951197005a317b099df3b6c2862603 + title:Anticipation (USA) + cheat + description:More time to answer questions + code:ZUUPYNPP + cheat + description:Less time to answer questions + code:YEUPYNPO + cheat + description:Infinite chances + code:AANZATEG + +cartridge sha256:bb834eb82f0ac53114035e6f353434a934d4aa47742644740de5fa8b2b033b5b + title:Arch Rivals - A Basketbrawl! (USA) + cheat + description:More time for a quarter + code:ALXLNZGU+ALNLPPGU + cheat + description:Less time for a quarter + code:ZLXLNZGL+ZLNLPPGL + cheat + description:Run faster without ball + code:AVNPLAAZ+ATVPAPAZ + cheat + description:Super speed + code:IXVOPAGA+IZSPGPGA + +cartridge sha256:751d3bf4722ce117d8ab7ff78059f42206ead5299716d91d5ff27d3900d555ad + title:Archon (USA) + cheat + description:Unrestricted ground movement + code:AASSIEUT + cheat + description:Unrestricted flying movement + code:AAKIGAGA + +cartridge sha256:7768ef85519c94dc40d09bc598121825d103fcf1d4927be59f597b0a3509d15f + title:Argus (Japan) + cheat + description:Invincibility + code:SZEOKASA + cheat + description:Infinite lives + code:SGXEYPVG + +cartridge sha256:a3763e702f8ae0818480cf0a8b2395d3f928c539f75e230ed43fa6b904fe6365 + title:Arkanoid (USA) + cheat + description:Infinite lives - both players + code:OZNEATVK + cheat + description:Infinite lives + code:SZNEATVG + cheat + description:No lasers + code:SXVATAAX + cheat + description:Square ball + code:VVZZPP + cheat + description:Start with 1 life - P1 + code:PAOPUGLA + cheat + description:Start with 6 lives - P1 + code:TAOPUGLA + cheat + description:Start with 9 lives - P1 + code:PAOPUGLE + cheat + description:Start on boss level + code:GZOONGPA + cheat + description:Start on level 0 + code:AAOONGPA + cheat + description:Start on level 1 + code:PAOONGPA + cheat + description:Start on level 2 + code:ZAOONGPA + cheat + description:Start on level 3 + code:LAOONGPA + cheat + description:Start on level 4 + code:GAOONGPA + cheat + description:Start on level 5 + code:IAOONGPA + cheat + description:Start on level 6 + code:TAOONGPA + cheat + description:Start on level 7 + code:YAOONGPA + cheat + description:Start on level 8 + code:AAOONGPE + cheat + description:Start on level 9 + code:PAOONGPE + cheat + description:Start on level 10 + code:ZAOONGPE + cheat + description:Start on level 11 + code:LAOONGPE + cheat + description:Start on level 12 + code:GAOONGPE + cheat + description:Start on level 13 + code:IAOONGPE + cheat + description:Start on level 14 + code:TAOONGPE + cheat + description:Start on level 15 + code:YAOONGPE + cheat + description:Start on level 16 + code:APOONGPA + cheat + description:Start on level 17 + code:PPOONGPA + cheat + description:Start on level 18 + code:ZPOONGPA + cheat + description:Start on level 19 + code:LPOONGPA + cheat + description:Start on level 20 + code:GPOONGPA + cheat + description:Start on level 21 + code:IPOONGPA + cheat + description:Start on level 22 + code:YPOONGPA + cheat + description:Start on level 23 + code:YPOONGPA + cheat + description:Start on level 24 + code:APOONGPE + cheat + description:Start on level 25 + code:PPOONGPE + cheat + description:Start on level 26 + code:ZPOONGPE + cheat + description:Start on level 27 + code:LPOONGPE + cheat + description:Start on level 28 + code:GPOONGPE + cheat + description:Start on level 29 + code:IPOONGPE + cheat + description:Start on level 30 + code:TPOONGPE + cheat + description:Start on level 31 + code:YPOONGPE + cheat + description:Start on level 32 + code:AZOONGPA + cheat + description:Start on level 33 + code:PZOONGPA + cheat + description:Start on level 34 + code:ZZOONGPA + cheat + description:Start on level 35 + code:LZOONGPA + cheat + description:Start on level 36 + code:GZOONGPA + +cartridge sha256:8593b6ae7b19b2e767ad2c207c5a83dea90030414f45eef4c0dec3c3a5530364 + title:Arkanoid II (Japan) + cheat + description:Infinite lives + code:SKSGXAVG + +cartridge sha256:381fcbe2b714c38fdeb4045d93f0867fe80f4a219077c3dc5a683a05a8b8e78a + title:Arkista's Ring (USA) + cheat + description:Infinite health + code:GZOPTIST + cheat + description:Less damage from powerful monsters + code:LAEPYSYA + cheat + description:Infinite lives + code:SZULXKVK + cheat + description:Start with fewer hearts + code:ZAKATIIA + cheat + description:Start with more hearts + code:PAKATIIE + cheat + description:Start with 20 continues + code:IPUAGSLA + cheat + description:Start with 5 continues + code:TAUAGSLA + cheat + description:Start with 1 life + code:PAKETILA + cheat + description:Start with 6 lives + code:TAKETILA + cheat + description:Start with 9 lives + code:PAKETILE + cheat + description:Infinite health (alt) + code:03D6:05 + cheat + description:Have Ring, Necklace, Mirror + code:03DC:FF + cheat + description:Have all armor + code:03D5:0A+03D6:0A + cheat + description:Have Ultimate Bow status + code:03D3:07 + cheat + description:Have Ultimate Arrow status + code:03D4:07 + cheat + description:Max item slots + code:03D7:03 + cheat + description:Unlock doors (enable only when at a door otherwise you'll move very slowly) + code:0001:FF + cheat + description:Have Fire Ball + code:0022:40 + cheat + description:Start on stage 02 + code:03D0:01 + cheat + description:Start on stage 03 + code:03D0:02 + cheat + description:Start on stage 04 + code:03D0:03 + cheat + description:Start on stage 05 + code:03D0:04 + cheat + description:Start on stage 06 + code:03D0:05 + cheat + description:Start on stage 07 + code:03D0:06 + cheat + description:Start on stage 08 + code:03D0:07 + cheat + description:Start on stage 09 + code:03D0:08 + cheat + description:Start on stage 10 + code:03D0:09 + cheat + description:Start on stage 11 + code:03D0:0A + cheat + description:Start on stage 12 + code:03D0:0B + cheat + description:Start on stage 13 + code:03D0:0C + cheat + description:Start on stage 14 + code:03D0:0D + cheat + description:Start on stage 15 + code:03D0:0E + cheat + description:Start on stage 16 + code:03D0:0F + cheat + description:Start on stage 17 + code:03D0:10 + cheat + description:Start on stage 18 + code:03D0:11 + cheat + description:Start on stage 19 + code:03D0:12 + cheat + description:Start on stage 20 + code:03D0:13 + cheat + description:Start on stage 21 + code:03D0:14 + cheat + description:Start on stage 22 + code:03D0:15 + cheat + description:Start on stage 23 + code:03D0:16 + cheat + description:Start on stage 24 + code:03D0:17 + cheat + description:Start on stage 25 + code:03D0:18 + cheat + description:Start on stage 26 + code:03D0:19 + cheat + description:Start on stage 27 + code:03D0:1A + cheat + description:Start on stage 28 + code:03D0:1B + cheat + description:Start on stage 29 + code:03D0:1C + cheat + description:Start on stage 30 + code:03D0:1D + cheat + description:Start on stage 31 + code:03D0:1E + +cartridge sha256:54526dc9444c0eb4b0e5814f98b5e522bcb9881a6f2c0644fc7a21ca8c03502b + title:Armadillo (Japan) + cheat + description:Invincibility + code:OXXUAKOK+AEXUPGLA + +cartridge sha256:20aaf9705d2cc17bac10468544afb250019f43983677b904ca88328f67aa9439 + title:Astro Fang - Super Machine (Japan) + cheat + description:Infinite fuel + code:SXESXPSA + cheat + description:Infinite Missiles + code:SZNUAZSA + +cartridge sha256:a08e6b53f1fa593e001719d87e2f203deb24ee1d389a8f3f339d75e9fb7c02f4 + title:Astyanax (USA) + cheat + description:Invincibility + code:EYNAGPEI + cheat + description:Infinite health + code:SZUGTISA + cheat + description:Infinite SP (spell) + code:AUEKGUAP + cheat + description:Double health and SP + code:AZKAVZGO + cheat + description:Keep weapons after death + code:SZUGEUVK + cheat + description:Start with Blast Spell + code:PAKEKZAA + cheat + description:Start with Bind Spell + code:ZAKEKZAA + cheat + description:Start with extra weapon power + code:GPKAXZGA + cheat + description:Start with 1 life + code:AEUEUGZA+AASAXZZA + cheat + description:Start with double lives + code:IEUEUGZA+IASAXZZA + cheat + description:Start with triple lives + code:AEUEUGZE+AASAXZZE + cheat + description:Invincibility (alt) + code:007D:03 + cheat + description:Infinie lives + code:0096:03 + +cartridge sha256:2137d1621d29df50100f4d0fba3bafa0be56ccd0c832e44cd29dd7f0d75b374e + title:Athena (USA) + cheat + description:Infinite health (after first 2 units) + code:GZUZLISA + cheat + description:Infinite time + code:AAULLYPA + cheat + description:Start with energy boost + code:AXKNYOGA + cheat + description:Start with extra time + code:YASVAYIA + cheat + description:Start with less time + code:GASVAYIA + cheat + description:Start with 1 life + code:AEKNLPZA + cheat + description:Start with 6 lives + code:IEKNLPZA + cheat + description:Start with 9 lives + code:AEKNLPZE + cheat + description:Infinite health + code:0095:0F + cheat + description:Infinite lives + code:009B:09 + cheat + description:Infinite time (alt) + code:0092:59 + +cartridge sha256:3b687bf0a8ccd23736bb7ed2e6e75f9d150318d79da22bbf7ff1dd97ab980957 + title:Attack of the Killer Tomatoes (USA) + cheat + description:Invincibility + code:AVTYTP + cheat + description:Infinite health + code:SXYYTO + cheat + description:Infinite lives + code:SKYYGK + cheat + description:Invincibility (alt) + code:07F4:32 + cheat + description:Infinite health (alt) + code:0722:3C + cheat + description:Infinite lives (alt) + code:0718:03 + +cartridge sha256:f3601248633f47a0ef10723e42a1072c76dd487d7ddf943e618611bb7cfec737 + title:Atlantis no Nazo (Japan) + cheat + description:Infinite lives + code:SUVEAOVK + cheat + description:Partial invincibility + code:SXOUYYAX+SZNUPZAX+SZOLPGAX+SXUAAPAX + +cartridge sha256:f91113b6a4bcd39d86ad5bbeaeb0f103461ada2cae513d1648a77ee575caf69b + title:Auto-Upturn (Asia) (PAL) (Unl) + cheat + description:Infinite health (blinking) + code:SXNZTLVG+SZXXLGVG + cheat + description:Infinite lives + code:SZOZTGVG + cheat + description:Infinite time + code:SXKPTIVG + +cartridge sha256:fb20d9562088cfa620ad0221e6e6f6c6d1f08e5a9cee2a97c0ef4fc39f050c6c + title:Baby Boomer (USA) (Unl) + cheat + description:Infinite lives + code:SGKTZXVK + +cartridge sha256:2bd744ff0d76653b9e218f6cea37f86bbdc6bc9b7a816c5fa236594ed1eb496a + title:Back to the Future (USA) + cheat + description:Invincibility - Street stages + code:AENEXZIA+AONENZYL+APUEKLEY + cheat + description:Disable all timers + code:AVVOUZSZ + cheat + description:Never lose a life in Hill Valley game + code:SZKEGOVK + cheat + description:Never lose a life in Cafe game + code:SXOELOVK + cheat + description:Never lose a life in School game + code:SXKALOVK + cheat + description:Never lose a life in Dancing Hall game + code:SXVELOVK + cheat + description:Start with 1 life + code:PEXEGAGA + cheat + description:Start with 8 lives + code:AEXEGAGE + +cartridge sha256:b265adba4a6f751f4da7b157672f324264f11fed3ca0b1e4ca703eb0b8a5ab77 + title:Back to the Future Part II & III (USA) + cheat + description:Infinite lives + code:SXXELOVK + cheat + description:Infinite fuel + code:GZEEPZST+GZOEZZST + cheat + description:Keep shots + code:GZKAKGSA + cheat + description:Quicker shots + code:PEKASEPO + cheat + description:Start with 20 nuclear fuel units + code:ZAXKYZPA + cheat + description:Start with 30 nuclear fuel units + code:LAXKYZPA + cheat + description:Start with 20 lives + code:ZAXKZZPA + cheat + description:Start with 30 lives + code:LAXKZZPA + +cartridge sha256:56382fac9104b26797de262a7c70ddd5850451d81a5008f3943d7bc492cbeb41 + title:Bad Dudes (USA) + cheat + description:Invincibility + code:AIEAZPAP+AVSOYOSZ+ELEAPOZE + cheat + description:Infinite health + code:APEETPEY + cheat + description:Infinite health (alt) + code:SZOEAOSE + cheat + description:Infinite lives + code:SZNKASVK + cheat + description:Infinite continues + code:GXOKASVK + cheat + description:Infinite time + code:SGVYOUVK + cheat + description:Hit anywhere + code:AAUPIOGI + cheat + description:One hit kills + code:AOUSNGEY + cheat + description:Start with 1 life and 1 continue + code:PENXYZLA + cheat + description:Start with double lives and continues + code:TENXYZLA + cheat + description:Start with triple lives and continues + code:PENXYZLE + cheat + description:Gain double usual energy from drinks + code:PESAIYIE + cheat + description:Have the Nunchaku + code:02A2:01 + cheat + description:Have the Knife + code:02A2:02 + cheat + description:One hit kills on bosses + code:032F:00+0344:00 + +cartridge sha256:467a2e53c7af4c60809db9c2670850a6e21a98ea37c1d920dc4fcb6afcb5a104 + title:Bad News Baseball (USA) + cheat + description:Play as girls team + code:PYEGZPLP+PAEGAPEP + cheat + description:Have 0 outs + code:050D:0 + cheat + description:Have 2 outs + code:050D:02 + cheat + description:Team 1 score is 0 + code:0305:0 + cheat + description:Team 2 score is 0 + code:0306:0 + +cartridge sha256:98658d5c8e530994730be6f4f7f76fe09142dee90e0afca613f5d6baaf208f52 + title:Bad Street Brawler (USA) + cheat + description:Infinite health + code:SUNGXOSO + cheat + description:Infinite time + code:SIXILYVI + cheat + description:Don't die at time out + code:SZOITNVK + cheat + description:Infinite lives + code:OZOIYPVK + cheat + description:Infinite lives (alt) + code:SGESGZVG + cheat + description:Start with 1 life + code:PAXITALA + cheat + description:Start with 6 lives + code:TAXITALA + cheat + description:Start with 9 lives + code:PAXITALE + cheat + description:Start on level 5 + code:GEUZZYAA + cheat + description:Start on level 10 + code:PEUZZYAE + cheat + description:Start on level 15 + code:TEUZZYAE + cheat + description:Infinite health (alt) + code:05F1:14 + +cartridge sha256:7328b2eb1c9fe06b98e0cba5c9058bf026e06a94900d490f79436d714eb48d6b + title:Balloon Fight (USA) + cheat + description:Infinite lives + code:SUNNIZVI + cheat + description:Start with only one balloon + code:PEUYTLZA + cheat + description:Balloons are unburstable + code:AVXTNYKA + cheat + description:Enemies can't burst balloons + code:LATTEX + cheat + description:Start with 1 life + code:AENYPPZA + cheat + description:Start with 6 lives + code:IENYPPZA + cheat + description:Start with 9 lives + code:AENYPPZE + cheat + description:Start on level 5 - 2P only + code:GENNIPAA + cheat + description:Start on level 10 - 2P only + code:PENNIPAE + cheat + description:Start on level 15 - 2P only + code:TENNIPAE + cheat + description:Infinite lives - P1 + code:0041:02 + cheat + description:Infinite lives - P2 + code:0042:02 + +cartridge sha256:d718f10d4ab57f7ed3891a84bdc496472a242b9c8496a3c0a0de77b45ae2fd58 + title:Banana Prince (Germany) + cheat + description:Invincibility + code:GAUXTAGZ + cheat + description:Invincible to enemies + code:AAXZKZAG + cheat + description:Invincible to shots + code:AESZOPAG + cheat + description:Invincible to lava + code:ASNLSZAL + cheat + description:Infinite energy + code:SGXXXOVK + cheat + description:Infinite lives + code:SKXSLUVK + cheat + description:Infinite time + code:SGXSYKVK + cheat + description:Infinite errors in quizes + code:SZSZSNVK + cheat + description:Max health when you die instead of 00 + code:GEXULGAE + cheat + description:Each Ring worth 10 + code:AYNGOIEP + cheat + description:Disable invincibility flickering + code:AIOSKZAP + cheat + description:Dice always at 9 in bonus island + code:PEUTITAE + cheat + description:Don't loose health when you touch lava + code:SZELVUVK + cheat + description:Start with 9 lives + code:PAVIOTLE + cheat + description:Start with max health + code:GANSOTTE + +cartridge sha256:bb30e4f4b1f6d8ccfdbd538b6f20347ed732cd37e8ac0a8305a277cf298b3dc8 + title:Barbie (USA) + cheat + description:Invincibility (blinks) + code:ESUSAIEY + cheat + description:Infinite Z's on Dream Meter + code:SXKSKNVK + cheat + description:Can re-enter Barbie's dream an infinite number of times + code:SZVAAVVK + cheat + description:Cannot re-enter Barbie's dream + code:AEEEYAZA + cheat + description:Start with 9 Z's (1st credit only) + code:PEEZEZIE + cheat + description:Start with 1 Z (1st credit only) + code:PEEZEZIA + +cartridge sha256:8bb20791eb3f4fd2455c33f0eead4538af3372205fba70fd4c3e0867b2c34c9a + title:Baseball Simulator 1.000 (USA) + cheat + description:Strike outs aren't allowed + code:OXVZITVV + cheat + description:Balls aren't counted + code:SZNAATVT + cheat + description:1 strike and you're out + code:PESEPTLA + cheat + description:2 strikes and you're out + code:ZESEPTLA + cheat + description:5 strikes and you're out + code:IESEPTLA + cheat + description:Strikes aren't counted + code:SZVAYTVT + cheat + description:1 ball and you walk + code:PESALTGA + cheat + description:2 balls and you walk + code:ZESALTGA + cheat + description:3 balls and you walk + code:LESALTGA + cheat + description:9 balls and you walk + code:PESALTGE + +cartridge sha256:5f8807999205f3800e445d6265b66fa6edff0070fc38905f7284f0ad437f9f53 + title:Baseball Stars II (USA) + cheat + description:Strikes do not count + code:SZSSZSVV + cheat + description:Balls do not count + code:SXSITKVV + cheat + description:One strike for an out + code:PAVIPILA + cheat + description:Two strikes for an out + code:ZAVIPILA + cheat + description:Four strikes for an out + code:GAVIPILA + cheat + description:Five strikes for an out (only 3 show on screen) + code:IAVIPILA + cheat + description:One ball for a walk + code:PESSIGGA + cheat + description:Two balls for a walk + code:ZESSIGGA + cheat + description:Three balls for a walk + code:LESSIGGA + cheat + description:Five balls for a walk (only 3 show on screen) + code:IESSIGGA + cheat + description:Six balls for a walk (only 3 show on screen) + code:TESSIGGA + cheat + description:One out per side instead of 3 (against human players) + code:PANILTLA + cheat + description:Two outs per side (against human players) + code:ZANILTLA + cheat + description:Four outs per side (against human players) + code:GANILTLA + cheat + description:One out per side instead of 3 (against computer) + code:PAOAILLA + cheat + description:Two outs per side (against computer) + code:ZAOAILLA + cheat + description:Four outs per side (against computer) + code:GAOAILLA + cheat + description:Game ends after 1 inning + code:PEXPVGLZ + cheat + description:Game ends after 2 innings + code:LEXPVGLZ + cheat + description:Game ends after 3 innings + code:TEXPVGLZ + cheat + description:Game ends after 4 innings + code:AEXPVGLX + cheat + description:Game ends after 5 innings + code:ZEXPVGLX + cheat + description:Game ends after 6 innings + code:GEXPVGLX + cheat + description:Game ends after 7 innings + code:TEXPVGLX + cheat + description:Game ends after 8 innings + code:AOXPVGLZ + +cartridge sha256:b9af9efdf490e14895e7980097a86d2f69d6396383773c221e77c6183a4ab9c8 + title:Bases Loaded II - Second Season (USA) + cheat + description:1 strike and you're out - most of the time + code:PEOGOALA + cheat + description:2 strikes and you're out - most of the time + code:ZEOGOALA + cheat + description:Outs aren't counted + code:SZOEVXVV + cheat + description:Only 2 outs allowed + code:PAOEUZZA + cheat + description:Only 1 out allowed + code:AAOEUZZA + cheat + description:Strikes aren't counted + code:SXNAXOVV+SXSGUKVV + cheat + description:Balls aren't counted + code:SZEEXXVV+SZEESXVV + +cartridge sha256:5d84d61e7e4c2b7d72a2b4599bd8cc415b71c90d1e332a83f95d96c75bc48efd + title:Bases Loaded 3 (USA) + cheat + description:Computer can't score + code:SZSYGNVV+SZSNTNVN + cheat + description:Some strikes aren't counted + code:SXOPSEVV + cheat + description:Balls aren't counted + code:SXKOXEVV + cheat + description:Strike outs aren't counted + code:SXOAIUVV + cheat + description:1 strike and you're out + code:AEOPXAZA + cheat + description:2 strikes and you're out + code:PEOPXAZA + cheat + description:Each strike out counts as 3 outs + code:PEOEGLLA + cheat + description:Each strike out counts as 2 outs + code:ZEOEGLLA + cheat + description:5 strike outs allowed + code:IEOEGLLA + cheat + description:9 strike outs allowed + code:PEOEGLLA + +cartridge sha256:e4aa19e0fd2800b58655eac814e1d9a9aa16d83eabd641789f8a6625591063a3 + title:Bases Loaded 4 (USA) + cheat + description:Balls do not count + code:SZNXGUVV + cheat + description:Strikes do not count + code:SXOXYUVV + cheat + description:2 strikes and you're out + code:PEOXGLZA + cheat + description:4 strikes and you're out + code:LEOXGLZA + cheat + description:1 ball and you walk + code:AANZGLLA + cheat + description:2 balls and you walk + code:PANZGLLA + cheat + description:3 balls and you walk + code:ZANZGLLA + cheat + description:Some batters start with count of 1 and 1 - 2P mode + code:PANPUTAA+PEOETGAA + cheat + description:Some batters start with count of 2 and 2 - 2P mode + code:ZANPUTAA+ZEOETGAA + +cartridge sha256:f28821df0114eb6cff1d7b4eadcee87713591709da1dd8b3525cf250156111f1 + title:Batman - The Video Game (USA) + cheat + description:Infinite health + code:PPOPEZVG + cheat + description:Infinite health (alt) + code:SKGGTT + cheat + description:Regenerates health meter (except Joker's gun) + code:SKGGGT + cheat + description:Infinite lives + code:SZUGGTVG + cheat + description:Infinite weapons + code:SXEPOGSA + cheat + description:Infinite bullets on pick-up + code:GZNOUGST + cheat + description:Hit anywhere + one hit kills + code:SZKPNUGK + cheat + description:Extra health on heart pick-up + code:GEEPOTPA + cheat + description:Double usual bullets on pick-up + code:GPSPXVZA + cheat + description:Half usual bullets on pick-up + code:IASPXVZA + cheat + description:Multi-jump + code:SNUPIKKI + cheat + description:Start with 1 life + code:AEESKGZA + cheat + description:Start with 6 lives + code:IEESKGZA + cheat + description:Start with 9 lives + code:AEESKGZE + cheat + description:Invincibility + code:00CC:A4 + cheat + description:Infinite health (alt 2) + code:00B7:08 + cheat + description:Infinite weapons (alt) + code:00B8:63 + cheat + description:Super gun (cannot change weapons) + code:00A6:FF + +cartridge sha256:183ede1115b428b046ae223f27e2db366a5b62c43f52b6fced5f22a57d39e663 + title:Batman - Return of the Joker (USA) + cheat + description:Invincible to bosses + code:SZVUIASE + cheat + description:Invincibility lasts until next stage + code:AAKOPIZA + cheat + description:Protection from enemy bullets + code:SZXZONSE + cheat + description:Protection from collisions + code:SZSZKXSE + cheat + description:Protection from electric grids + code:SXSATXSE + cheat + description:Infinite lives + code:SZXSZSVK + cheat + description:Each Backpack Energy Capsule counts as two + code:GAVXVLZA + cheat + description:Each Backpack Energy Capsule counts as four + code:AAVXVLZE + cheat + description:Don't get stunned when hit + code:GXEUIOSE + cheat + description:Stand your ground + code:AEUUAPGA+GXKLAOKE + cheat + description:Intense knock-back when hit (may get stuck if you knock back into a wall) + code:VNULTONN+PEUUGPAA + cheat + description:Continue game with 3 life increments instead of 8 + code:GASOTOTA + cheat + description:Start with 7 Backpack Energy Capsules instead of none + code:GEOSPKVN + cheat + description:Start with 3 life increments instead of 8 + code:GEOSTKTA + cheat + description:Start with 1 life + code:AEXILGZA + cheat + description:Start with 100 lives + code:GVXILGZA + cheat + description:Invincibility after first hit + code:0479:00 + cheat + description:Infinite health + code:0478:08 + cheat + description:Bosses lose health quickly + code:00AA:00 + +cartridge sha256:8b7363e037883aaa36d2c643c36a6f09ce49bd515f166154bd2a48e0a6468b9d + title:Batman Returns (USA) + cheat + description:Infinite Batarangs + code:SXSKGKVK + cheat + description:Don't lose health from spin attack + code:AAVASZZA + cheat + description:Almost infinite lives and health + code:GZEGLVSE + cheat + description:Small hearts give more health + code:AUSAPPAP + cheat + description:Power punch + code:YAKZTIZE + cheat + description:Power slide attack + code:YAKXLIIE + cheat + description:Power jump kick + code:ZPKXZIIE + cheat + description:Walk faster horizontally + code:GESAKIPA+GEVEVIPA + cheat + description:Start with 9 Batarangs + code:PAXELAIE + cheat + description:Start with full health + code:YLOALEAX + cheat + description:Start with less health + code:APOALEAZ + cheat + description:Invincibility (blinking) + code:04C8:15 + cheat + description:Infinite health + code:0140:41 + cheat + description:Infinite Batarangs (alt) + code:0141:09 + cheat + description:0 health - Enemy 1 + code:0145:00 + cheat + description:0 health - Enemy 2 + code:0146:00 + cheat + description:0 health - Enemy 3 + code:0147:00 + +cartridge sha256:64832bef6533d98f49e807c000537c8cb26ef94e6c3f871b8b6b35c5a11e427b + title:Battle City (Japan) + cheat + description:Infinite freeze time once you obtain a clock + code:SZEIEKVK + cheat + description:256 seconds of freeze time once you obtain a clock + code:NNNTVOZE + +cartridge sha256:a50c0b6d93f7e20ecfd8a95abd5b7bccd4cf290901376fcf9e4053b3f964fca1 + title:Battle Formula (Japan) + cheat + description:Infinite life + code:SXSOEZSA + +cartridge sha256:d095eab5376c2b7c4f1c09018c9591598831c557e0b691c01ca2480e49e60c0a + title:Battle of Olympus, The (USA) + cheat + description:Start with less stamina + code:AAUGPAAO + cheat + description:Start with more stamina + code:AZUGPAAP + cheat + description:Start with Sandals of Hermes + code:AAEGOZZA + cheat + description:Start with Staff of Fennel + code:PAUGYAAA+GZUKGASA+GZUKTASA + cheat + description:Start with Sword + code:ZAUGYAAA+GZUKGASA+GZUKTASA + cheat + description:Start with Divine Sword + code:LAUGYAAA+GZUKGASA+GZUKTASA + +cartridge sha256:c49a5d7f565646d76bdc307ccb0202197f579b77c5bf5ea409b5cb29f72edf3a + title:Battleship (USA) + cheat + description:1 round per level + code:PEUAUGIA + cheat + description:3 rounds per level + code:LEUAUGIA + cheat + description:Each ship can take only one hit + code:SZUAOSOU + cheat + description:You only have RIM-66 missiles + code:SAXAOISP + cheat + description:Start on level 2 + code:PASAKGAA+VASEOGSA+VASASGSA + cheat + description:Start on level 3 + code:ZASAKGAA+VASEOGSA+VASASGSA + cheat + description:Start on level 4 + code:LASAKGAA+VASEOGSA+VASASGSA + cheat + description:Start on level 5 + code:GASAKGAA+VASEOGSA+VASASGSA + cheat + description:Start on level 6 + code:IASAKGAA+VASEOGSA+VASASGSA + cheat + description:Start on level 7 + code:TASAKGAA+VASEOGSA+VASASGSA + cheat + description:Start on level 8 + code:YASAKGAA+VASEOGSA+VASASGSA + +cartridge sha256:a2039efb5b5b8d4941c31ae0977dacccec5aaa72fe307ae36af2a454d30d9e26 + title:Battletank (USA) + cheat + description:Infinite energy + code:SKOPAAVT + cheat + description:Infinite hits + code:SXOPAAVT+SXSLNPSA + cheat + description:Infinite fuel + code:SKUAANSE + cheat + description:Infinite weapons + code:SIXTEEVS+SGKVINVK + cheat + description:Infinite ammo + code:SLXTEEVS + cheat + description:Start with half 150mm ammo + code:TOVZIAZL + cheat + description:Start with double 150mm ammo + code:LVVZIAZL + cheat + description:Start with more wire guided shells + code:ZUVXTAPA + cheat + description:Start with max wire guided shells + code:LVVXTAPA + cheat + description:Start with more smoke shells + code:ZUNXAAPA + cheat + description:Start with max smoke shells + code:LVNXAAPA + cheat + description:Start with less 50mm shells + code:LGEZPPVO + cheat + description:Start with max 50mm shells + code:NYEZPPVO + cheat + description:Start with less 50mm ammo after mission 5 + code:GTEZIOEG + cheat + description:Start with max 50mm ammo after mission 5 + code:NYEZIOEK + +cartridge sha256:56d25e05dde2048c3a9b4e36ab5325091310ce2b65171615b5596fc542db66fa + title:Battletoads (USA) + cheat + description:Infinite lives + code:GXXZZLVI + cheat + description:One hit kills + code:OUAILU + cheat + description:Enemies easier to kill + code:GXEILUSO + cheat + description:Mega-jumping + code:EYSAUVEI + cheat + description:Double health from flies + code:AOUKXNAA + cheat + description:Maximum health from flies + code:YXUKXNAE + cheat + description:Super fast punching + code:AEUZITPA + cheat + description:Start with 1 life + code:PENVZILA + cheat + description:Start with 6 lives + code:TENVZILA + cheat + description:Start with 9 lives + code:PENVZILE + cheat + description:Start on level 2 - Wookie Hole + code:ZAXAALAA + cheat + description:Start on level 3 - Turbo Tunnel + code:LAXAALAA + cheat + description:Start on level 4 - Arctic Cavern + code:GAXAALAA + cheat + description:Start on level 5 - Surf City + code:IAXAALAA + cheat + description:Start on level 6 - Karnath's Lair + code:TAXAALAA + cheat + description:Start on level 7 - Volkmire's Inferno + code:YAXAALAA + cheat + description:Start on level 8 - Intruder Excluder + code:AAXAALAE + cheat + description:Start on level 9 - Terra Tubes + code:PAXAALAE + cheat + description:Start on level 10 - Rat Race + code:ZAXAALAE + cheat + description:Start on level 11 - Clinger Winger + code:LAXAALAE + cheat + description:Start on level 12 - The Revolution + code:GAXAALAE + cheat + description:Invincibility + code:0574:02 + cheat + description:Infinite lives (alt) + code:0011:05 + +cartridge sha256:4f67a81cc978e5aaf8aa03046c27ddc954f835e2110e346bc28d35f6b4ac61ca + title:Battletoads-Double Dragon (USA) + cheat + description:Infinite lives (except stage 4) + code:GXXLAAVI + cheat + description:Infinite lives on stage 4 + code:GZSOXPVI + cheat + description:Bonus score now gives invincibility (instead of invincibility pod) + code:IYKNIKGX + cheat + description:Longer invincibility + code:YPSYPGIE + cheat + description:Even longer invincibility + code:ILSYPGIA + cheat + description:Double Dragon super punch + code:AOSEVAZA + cheat + description:Battletoads super punch + code:AOUEUAGA + cheat + description:Stronger enemies + code:AXUIPOYA + cheat + description:Start with 10 continues + code:PEVELZZE + cheat + description:Start with full lives + code:IEEOOALA + cheat + description:Start with 1 life + code:AEEOOALA + cheat + description:Infinite lives - P1 + code:0011:05 + cheat + description:Infinite lives - P2 + code:0012:05 + cheat + description:0 hits to SMASH! enemies + code:051C:00+051D:00+051E:00+051F:00+0520:00+0521:00 + +cartridge sha256:3b3865e6e44f8ef749e8a9509651a6fad688b8d744fab22974a6f4cb9e7f2b0b + title:Beauty and the Beast (Europe) + cheat + description:Infinite hits + code:SLNKKYVK + cheat + description:Infinite lives + code:SUESZGVK + cheat + description:Infinite time + code:SUXSAZVV + +cartridge sha256:b9434d2f359f6e464da36fbcf6d9eb794b7edff03b89467d1609158f13bfef52 + title:Beetlejuice (USA) + cheat + description:Invincibility + code:EIEISGEY + cheat + description:Invincibility (blinking) + code:SZOSYNSE + cheat + description:Infinite hits + code:AAOITYPA + cheat + description:Infinite lives + code:SZOIYKVK + cheat + description:Take fewer hits to die + code:PEOAIAZA+PENSYLZA + cheat + description:Start with 1 life + code:PEOAAALA + cheat + description:Start with 6 lives + code:TEOAAALA + cheat + description:Start with 9 lives + code:PEOAAALE + +cartridge sha256:f93163a51f4a671c5f4da390d4d286d6d8440d87dfe24285c40ed73dc422bf7d + title:Bee 52 (USA) (Unl) + cheat + description:Invincibility + code:EINTILEY + cheat + description:Invincibility (alt) + code:SXNTLPSA + cheat + description:Infinite lives + code:SXSGOSVK + cheat + description:Keep pick-ups + code:SZXNXTAX + cheat + description:Don't get stunned + code:GZSSTTEI + cheat + description:Fly quicker + code:GXNKNTAL+GZOKUYAP + cheat + description:Start with 1 life + code:PAXYKGLA + cheat + description:Start with 6 lives + code:TAXYKGLA + cheat + description:Start with 9 lives + code:PAXYKGLE + +cartridge sha256:2366af9fc0512d39bfa6e908b4caa12be3d21225af49274ffe2ff51cf0b9c1e6 + title:Best of the Best - Championship Karate (USA) + cheat + description:Infinite time (round never ends) + code:SXVSAZVG + cheat + description:Each round is 0:10 instead of 1:00 + code:AANIGYPA+VTNIPYSA + cheat + description:Each round is 0:20 + code:AANIGYPA+OZVSYYSE+ZANIANTI + cheat + description:Each round is 0:30 + code:AANIGYPA+OZVSYYSE+LANIANTI + cheat + description:Each round is 0:40 + code:AANIGYPA+OZVSYYSE+GANIANTI + cheat + description:Each round is 0:50 + code:AANIGYPA+OZVSYYSE+IANIANTI + cheat + description:Each round is 2:00 + code:ZANIGYPA + cheat + description:Each round is 3:00 + code:LANIGYPA + cheat + description:Each round is 4:00 + code:GANIGYPA + cheat + description:Each round is 5:00 + code:IANIGYPA + cheat + description:Each round is 6:00 + code:TANIGYPA + cheat + description:Each round is 7:00 + code:YANIGYPA + cheat + description:Each round is 8:00 + code:AANIGYPE + cheat + description:Each round is 9:00 + code:PANIGYPE + cheat + description:Each match is 1 round instead of 5 + code:PAOSUZIA + cheat + description:Each match is 2 rounds + code:ZAOSUZIA + cheat + description:Each match is 3 rounds + code:LAOSUZIA + cheat + description:Each match is 4 rounds + code:GAOSUZIA + cheat + description:Each match is 6 rounds + code:TAOSUZIA + cheat + description:Gain more strength and reflex points in training + code:AAEVVAGE+AEETOPZA + cheat + description:Gain more resistance points in training + code:APEVVAGA+AEETOPZA + cheat + description:All physical types are 30 (causes graphic errors near top of screen) + code:OXNSGIOU+TONSIIZE + cheat + description:All physical types are 50 (causes graphic errors near top of screen) + code:OXNSGIOU+ZUNSIIZA + cheat + description:Start with 50 resistance points + code:ZLEAZETP + cheat + description:Start with 50 strength points + code:ZLEAPEAZ + cheat + description:Start with 50 reflex points + code:ZLEALAGP + cheat + description:Start with 70 resistance points + code:TGEAZETP + cheat + description:Start with 70 strength points + code:TGEAPEAZ + cheat + description:Start with 70 reflex points + code:TGEALAGP + +cartridge sha256:18c134f8cc7effc0b90dcca86a27c305cbd7dadfb159689c89790c7fe4ff9b77 + title:Bible Adventures (USA) (v1.4) (Unl) + cheat + description:Infinite health + code:SUVIKXSO + +cartridge sha256:b56f867ad6b067f9ca7e46afb8e7a953fa281404232e2497c88e43448a2c3a57 + title:Bible Adventures (USA) (v1.3) (Unl) + cheat + description:Infinite health + code:SUVSEXSO + +cartridge sha256:981b39b22c9b17055c90a612b9c8ea6711541ff5196018043f3516ed238f3ce9 + title:Bible Adventures (USA) (v1.2) (Unl) + cheat + description:Infinite health + code:SUNSVXSO + +cartridge sha256:88ee64119746de659f70f3d459c62dd2af3b21f29f5064ea14f0fb03904cbcfe + title:Bible Adventures (USA) (v1.1) (Unl) + cheat + description:Infinite health + code:SUXIUXSO + +cartridge sha256:2807c405f072a1e828cbdd4812822ec301979472fd9b8c6225aa4d1dca89613c + title:Bible Adventures (USA) (Unl) + cheat + description:Infinite health + code:SLOSGVSO + +cartridge sha256:32fa00d52f39b053c30061d6789944fc61c0c88c885bd8248ff5771fd2f78ae6 + title:Bigfoot (USA) + cheat + description:Infinite nitros + code:SUKXVUVS + cheat + description:Longer nitro boost + code:NNKXXLGV + cheat + description:Shorter nitro boost + code:AXKXXLGT + cheat + description:Engines are half price + code:GEKAOKAA + cheat + description:Engines cost more + code:PEKAOKAE + cheat + description:Tires are half price + code:LEKAXGTA + cheat + description:Tires cost more + code:PEKAXGTE + cheat + description:Transmission work is half price + code:ZEKAUGGA + cheat + description:Transmission work is double price + code:AEKAUGGE + cheat + description:Suspension is half price + code:PEKAKGZA + cheat + description:Suspension is triple price + code:TEKAKGZA + cheat + description:P1 gets P2's nitros + code:VTVUYOVN+SZVUAOSE + +cartridge sha256:d290ac95ca512a37380cd534394ad600109a8eb97651f50e46e45c2eb5fb405c + title:Big Nose the Caveman (USA) (Unl) + cheat + description:Invincibility + code:SXNNEISA + cheat + description:Infinite lives + code:SXOTPAVG + cheat + description:Infinite lives (alt) + code:SUOTPAVK + cheat + description:Slower timer + code:ANENAKLL + cheat + description:Faster timer + code:AXENAKLL + cheat + description:Never lose bones when buying + code:AEEYYZPA + cheat + description:Always enable instant win level + code:EIXVIPEY + cheat + description:Start on Monster Island + code:XXXYITSZ+VEKYAVSE+AOUGTAE + cheat + description:Start on Terror Island + code:XXXYITSZ+VEKYAVSE+ZOUGTAE + cheat + description:Start with 1 life + code:PEUYITLA + cheat + description:Start with 6 lives + code:TEUAITLA + cheat + description:Start with 9 lives + code:PEUYITLE + +cartridge sha256:b183c0952994cadc1c8d6dd290730f43ecacb051d3dfe53784578635a1049455 + title:Bill & Ted's Excellent Video Game Adventure (USA) + cheat + description:Infinite skeleton keys + code:SZKUPXVK + cheat + description:Infinite coins for locals + code:SZEKUOSE + cheat + description:Infinite Good Stuff + code:OUOOUEOO + cheat + description:Phone call segments cost only 1 coin + code:SXOTTOSE + cheat + description:Ted starts with 99 coins instead of 15 + code:OOKKUTIO + cheat + description:Bill starts with 99 coins + code:OOSVAPIO + cheat + description:Ted starts with 5 coins + code:IEKKUTIP + cheat + description:Bill starts with 5 coins + code:IESVAPIP + +cartridge sha256:ddf58f90fa5966137e71a0f30a162bf03b3e8b1b99f4f1d16cac26d5e2cf5b35 + title:Bill Elliott's NASCAR Challenge (USA) + cheat + description:Accelerate faster + code:EUEKTLEP + cheat + description:Infinite 'free time' in the pits + code:SZUETKVK + cheat + description:Freeze timer while crew works on car in pits + code:SXOAZVVK + +cartridge sha256:4f59f3ef6045be753ed5f7988e4b302b7f71216354a644f760f4a0aa43af7d22 + title:Bio Force Ape (Japan) (En) (Proto) + cheat + description:Infinite health + code:SZSUNXSE + cheat + description:Walk through walls + code:ATEPAVAL+AVUPAVAL + cheat + description:Start on level 2 + code:PAXAYGAA + cheat + description:Start on level 3 + code:ZAXAYGAA + +cartridge sha256:aeb61fd5cf5a5ed73344c46a43f8a8d539f601ff57e8f56c49bc1caea4ab3d9e + title:Bionic Commando (USA) + cheat + description:Invincibility + code:AVSTYNVG + cheat + description:Infinite lives in main game + code:SZNUIYVG + cheat + description:Infinite lives in sub-game + code:SXUEZPVG + cheat + description:Don't take damage from bullets and collisions + code:SXSTYNVK + cheat + description:Don't take damage from spikes + code:VTNZXVVK + cheat + description:Don't take damange from bullets and collisions in sub-game + code:SZUOAOVK + cheat + description:Autofire - main game + code:XYXUUOEN + cheat + description:Use with BIO Code 11 for im-proved autofire with normal gun + code:AAKUOOZA + cheat + description:Start with 3 life energy capsules + code:LAUKOZAA+XTUKUXVU + cheat + description:Start with 1 life + code:AAUGSZZA + cheat + description:Start with double lives + code:IAUGSZZA + cheat + description:Start with triple lives + code:AAUGSZZE + cheat + description:Start with 3-way gun + code:VGKKNXUK + +cartridge sha256:abde6fc87b2d90e0b40cd3420d4b7381e1f23285efbbdc62fd27b59c591ad2cc + title:Blades of Steel (USA) + cheat + description:Invincible in minigame + code:AINXIYEI + cheat + description:Faster timer + code:GEUGTTYA + cheat + description:Slower timer + code:GOUGTTYA + cheat + description:Player with puck don't slow down + code:AAOSSAAZ + cheat + description:Players can take only one punch + code:PAXZLGIA + cheat + description:Players 2/CPU don't throw punches + code:OXKXTVPK+SXSZZSSU + cheat + description:Start a new game to view the ending + code:YASGITLA + +cartridge sha256:7a26c62a9b1605cbedf7cd5b2672aa0fc15b688b227a6cb57dbf74aa71a05f1c + title:Blaster Master (USA) + cheat + description:Infinite car health + code:XVLAKO + cheat + description:Enemies are killed instantly + code:YAASLY + cheat + description:Infinite lives + code:SZUGYIVG + cheat + description:Infinite Hover + code:SZXOALVG + cheat + description:Infinite Homing Missiles + code:GZSOEEVK + cheat + description:Infinite Thunderbreaks + code:GXKPEOVK + cheat + description:Infinite Multi-Warheads + code:GXSOVXVK + cheat + description:Start with all abilities + code:NNKKGZAE + cheat + description:Start with 5 of each weapon + code:IAEKPLAA + cheat + description:Start with 10 of each weapon + code:ZAEKPLAE + cheat + description:Start with 15 of each weapon + code:YAEKPLAE + cheat + description:Start with 99 of each weapon + code:LTEKPLAA + cheat + description:Start with 99 of each weapon and max Hover + code:NYEKPLAE + cheat + description:Start with 1 life + code:AAEGZLZA + cheat + description:Start with 6 lives + code:IAEGZLZA + cheat + description:Start with 9 lives + code:AAEGZLZE + cheat + description:Start on world 2 + code:PENKTXAE + cheat + description:Start on world 3 + code:ZENKTXAE + cheat + description:Start on world 4 + code:LENKTXAE + cheat + description:Start on world 5 + code:GENKTXAE + cheat + description:Start on world 6 + code:IENKTXAE + cheat + description:Start on world 7 + code:TENKTXAE + cheat + description:Start on world 8 + code:YENKTXAE + cheat + description:Start at the boss of world 1 + code:OXNKIXPE+AENKTXAA + cheat + description:Start at the boss of world 2 + code:OXNKIXPE+PENKTXAA + cheat + description:Start at the boss of world 3 + code:OXNKIXPE+ZENKTXAA + cheat + description:Start at the boss of world 4 + code:OXNKIXPE+LENKTXAA + cheat + description:Start at the boss of world 5 + code:OXNKIXPE+GENKTXAA + cheat + description:Start at the boss of world 6 + code:OXNKIXPE+IENKTXAA + cheat + description:Start at the boss of world 7 + code:OXNKIXPE+TENKTXAA + cheat + description:Start at the boss of world 8 + code:OXNKIXPE+YENKTXAA + cheat + description:Die to see ending + code:ZGUKZITP + cheat + description:Invincibility + code:007E:00 + cheat + description:Infinite health (alt) + code:040D:FF + cheat + description:Infinite Hover (alt) + code:0092:FF + cheat + description:Infinite lives (alt) + code:00DD:03 + cheat + description:Infinite Homing Missiles (alt) + code:06F0:63 + cheat + description:Infinite Thunderbreaks (alt) + code:06F1:63 + cheat + description:Infinite Multi-Warheads (alt) + code:06F2:63 + cheat + description:Full Gun Power - Jason + code:00C3:FF + cheat + description:Most end bosses die instantly + code:047D:00 + +cartridge sha256:e311f33f98a4461f9ca79e2df863323d42572234bc59321bb9fb39ca1b18d0cf + title:Blue Marlin, The (USA) + cheat + description:Line is a 1000 yards long + code:GENTUIZA + cheat + description:Catch fish right after they bite - most of the time + code:AESVOXEG + cheat + description:When fish bite they are close to the boat + code:PESVOXEK + cheat + description:Line is set to 153 feet + code:OOSVOXEK + cheat + description:Pull fish in quicker + code:PESVXIAA + cheat + description:Vitality always at max + code:OZSVKKPV+YASVSGPE + +cartridge sha256:46fb05f80167bd185bd6eef40e1f86a0dcdd36e250ef8e2b29a575550d75473a + title:Blues Brothers, The (USA) + cheat + description:Invincibility + code:EIVTVIEY+EIXTAGEY + cheat + description:Infinite health + code:SUOVAEVS + cheat + description:Infinite lives + code:SUUVYEVS + cheat + description:Invincibility (alt) (blinking) + code:03C2:02 + cheat + description:Infinite energy (alt) + code:042A:03 + cheat + description:Infinite lives (alt) + code:0428:02 + +cartridge sha256:2967746c2a434c97a074b14d894ea132fab8e443899f6ca870718eeee1669039 + title:Bomberman (USA) + cheat + description:Immune to explosions + code:OXVGITSX + cheat + description:Infinite time + code:SZIGAT + cheat + description:Infinite lives + code:SXPKAG + cheat + description:Never lose Detonator once obtained + code:GXEKLGSA + cheat + description:Increase Bomb detonation time + code:NYXKUIEX + cheat + description:Reduce Bomb detonation time + code:AYXKUIEZ + cheat + description:Use up to 10 Bombs + code:XZEGNIVZ+PAEKEIGN + cheat + description:Walk through walls + code:OZNKNNPK+AEEGEYPA + cheat + description:Decrease time + code:VPGKGG + cheat + description:Increase timer + code:VYGKGK + cheat + description:Start with double power Bomb blasts + code:AXKKALAP + cheat + description:Start with triple power Bomb blasts + code:AUKKALAP + cheat + description:Start with maximum power Bomb blasts + code:EEKKALAP + cheat + description:Start with Detonator, max Bomb power and use up to 10 Bombs + code:AESKGUIZ + cheat + description:Start with and keep Detonator + code:OXEKVPSX+AESKNKTA + cheat + description:Start with 1 life + code:AEZKLL + cheat + description:Start with 10 lives + code:PEZKLU + cheat + description:Start on stage 10 + code:ZELGYU + cheat + description:Start on stage 20 + code:GOLGYL + cheat + description:Start on stage 30 + code:TOLGYU + cheat + description:Start on stage 40 + code:AXLGYU + cheat + description:Start on stage 50 + code:ZULGYL + cheat + description:Invincibility + code:005C:00 + cheat + description:Immune to explosions (alt) + code:0079:01 + cheat + description:Infinite time (alt) + code:0093:EE + cheat + description:Infinite lives (alt) + code:0068:09 + cheat + description:Max Bomb power + code:0073:80 + cheat + description:Use up to 10 Bombs (alt) + code:0074:0A + cheat + description:Walk through walls (alt) + code:0076:01 + cheat + description:Have Detonator + code:0077:01 + cheat + description:Start on stage 50 (alt) + code:0058:32 + +cartridge sha256:83cb47fda376900e8c1d8eef5c413229fb6cacaff43201afd421c71610c20368 + title:Bomberman II (USA) + cheat + description:Infinite lives + code:GXKGKXVK + cheat + description:Infinite time + code:GXXONEVK + cheat + description:Super start + code:GAXKSTAA+GASKKTAA + cheat + description:Immune to explosions + code:OXXAPYSX+PEXAZNVZ + cheat + description:Walk through walls + code:OXOEGYSX+PEOEINSZ + cheat + description:Always have Detonator + code:AEKAZYLA + cheat + description:Slower timer + code:LVXOUELL + cheat + description:Faster timer + code:TOXOUELU + cheat + description:Bomb has a longer fuse + code:YNEOLXLK + cheat + description:Bomb has a shorter fuse + code:AXEOLXLG + cheat + description:Stop Bombs from exploding + code:GXOLSXVS + cheat + description:Dollar sign acts as flame face + code:EASPTANG + cheat + description:Dollar sign acts as Bomb + code:GYSPTANG + cheat + description:Dollar sign acts as heart with Bomb + code:KASPTANK + cheat + description:Dollar sign acts as skate + code:OPSPTANG + cheat + description:Dollar sign acts as vest for a short time + code:OZSPTANK + cheat + description:Start with 1 life + code:AEEGEPZA + cheat + description:Start with 6 lives + code:IEEGEPZA + cheat + description:Start with 9 lives + code:AEEGEPZE + cheat + description:Invincibility (except in normal game) - P1 + code:0069:05 + cheat + description:Invincibility (except in normal game) - P2 + code:006A:05 + cheat + description:Invincibility (except in normal game) - P3 + code:006B:05 + cheat + description:Infinite time (hundred's digit) + code:0559:09 + cheat + description:Infinite time (ten's digit) + code:055A:09 + cheat + description:Infinite time (one's digit) + code:055B:09 + cheat + description:Infinite lives - P1 + code:04E5:09 + cheat + description:Max Bomb power - P1 + code:0093:0C + cheat + description:Max Bomb power - P2 + code:0094:0C + cheat + description:Max Bomb power - P3 + code:0095:0C + cheat + description:Max Bomb quantity - P1 + code:0090:0C + cheat + description:Max Bomb quantity - P2 + code:0091:0C + cheat + description:Max Bomb quantity - P3 + code:0092:0C + +cartridge sha256:b3d82e2818aea6caa69dcfe7d56197a7a51afe87819527880cf08876d1a988de + title:Bonk's Adventure (USA) + cheat + description:Infinite lives + code:SZVZINVK + cheat + description:Super-jump when normal + code:GXEEYEGA + cheat + description:Keep "speed up" after powered down + code:GXVPIKSE + cheat + description:Gain energy from picking up smiles + code:GASZTYAA + cheat + description:Start with less initial energy (but more maximum energy) + code:GEUAAEGA + cheat + description:Start with more energy + code:AOUAAEGE + cheat + description:Start with 1 life + code:AEKAAAZA + cheat + description:Start with 6 lives + code:IEKAAAZA + cheat + description:Start with 9 lives + code:AEKAAAZE + cheat + description:Start on stage 2-1 + code:YEXELAAA + cheat + description:Start on stage 3-1 + code:IEXELAAE + cheat + description:Start on stage 4-1 + code:ZOXELAAA + cheat + description:Start on Stage 5-1 + code:YOXELAAA + cheat + description:Start on stage 6-1 + code:PXXELAAA + +cartridge sha256:0e58f270e7b116782e0822f52058eff66465df49527c6f8c6f0eca994d8cae7a + title:Boulder Dash (USA) + cheat + description:Infinite lives + code:SLEZXTVI + cheat + description:Infinite time + code:SXSGSYAX + cheat + description:Speed up timer + code:YOSGXNYU + cheat + description:Slow down timer + code:NNSGXNYU + cheat + description:1 life after continue + code:PEOXEYLA + cheat + description:6 lives after continue + code:TEOXEYLA + cheat + description:9 lives after continue + code:PEOXEYLE + cheat + description:Start with 1 life + code:PAKIELLA + cheat + description:Start with 6 lives + code:TAKIELLA + cheat + description:Start with 9 lives + code:PAKIELLE + +cartridge sha256:911fb75ec1f900a5c258635fae79e56520eeb4aec35b40737c44b735eeccdc56 + title:Boy and His Blob, A - Trouble on Blobolonia (USA) + cheat + description:Invincible (restart if you die underwater and get stuck by being unable to call your Blob) + code:AVOGAEOZ + cheat + description:Never take damage from enemies + code:AVOPVGEI + cheat + description:Infinite lives + code:GXXEOPVG + cheat + description:Infinite Jellybeans + code:AAVKIPPA + cheat + description:1 life only + code:AAULNGIA + cheat + description:Double lives + code:ZAULNGIE + cheat + description:Fast play + code:SXEEZAAX + cheat + description:Gives 10 Orange Jellybeans + code:APEUUIAA + cheat + description:10 Lime Jellybeans + code:AONUSGAA + cheat + description:99 Licorice Jellybeans + code:OONLOGZN + cheat + description:Double Strawberry Jellybeans + code:AUNLUGIP + cheat + description:Double Cola Jellybeans + code:TUNLNKAP + cheat + description:Double Cinnamon Jellybeans + code:AKNUOGGX + cheat + description:Double Apple Jellybeans + code:GXNUUGZP + cheat + description:Double Vanilla Jellybeans + code:AVNUNGAL + cheat + description:Double Ketchup Jellybeans + code:ZPELNITA + cheat + description:Triple Coconut Jellybeans + code:AONLSGTE + cheat + description:Triple Rootbeer Jellybeans + code:APELUITE + cheat + description:10 Vitamin A for Vita-Blaster + code:APEUSIAA + cheat + description:10 Vitamin B for Vita-Blaster + code:APEUNIAA + cheat + description:10 Vitamin C for Vita-Blaster + code:APOLOIAA + cheat + description:Start with 101 of all starting Jellybeans + code:SZXLXKSU+YYXLUGEY + +cartridge sha256:a8b6829d8d1e17cc23c8815e0b0add09e26fc5a2a27ad6bba260cef926535af2 + title:Bram Stoker's Dracula (USA) + cheat + description:Invincibility + code:ASVIAPEI + cheat + description:Invincibility after getting hit + code:SZKLVZAX + cheat + description:Infinite health (except falling off cliffs) + code:SUXLISVS + cheat + description:Infinite health + code:SXXLISVS + cheat + description:Infinite lives + code:NUNTZUKU + cheat + description:Infinite lives (alt) + code:SXNTPUVK + cheat + description:Infinite time + code:AEVGPPPA + cheat + description:Infinite time (alt) + code:SXNKGOSE+SXNGYOSE + cheat + description:Infinite ammo + code:SZNVVSVK + cheat + description:Infinite weapons (except scene 1 daytime) + code:UUETEIZE + cheat + description:Faster timer + code:ZEVGPPPA + cheat + description:Always have 63 ammo + code:AANGYZIA + cheat + description:Disable axe + code:NNSNGPZE + +cartridge sha256:e1487d23800aa2c29cb9da6f2bf538aa10044930ef566d087f7acf1aa649fb9e + title:BreakThru (USA) + cheat + description:Infinite lives - both players + code:GZUKYPVG + cheat + description:Infinite weapon time + code:GZKSLZVG + cheat + description:Start each life with 3-way firing and 99 seconds + code:LTUKTLAA + cheat + description:Start with 1 life - P1 + code:PEUKPZLA + cheat + description:Start with 6 lives - P1 + code:TEUKPZLA + cheat + description:Start with 9 lives - P1 + code:PEUKPZLE + cheat + description:Start with 1 life - P2 + code:PEKGGZLA + cheat + description:Start with 6 lives - P2 + code:TEKGGZLA + cheat + description:Start with 9 lives - P2 + code:PEKGGZLE + cheat + description:Start on level 2 + code:ZANKLZPA + cheat + description:Start on level 3 + code:LANKLZPA + cheat + description:Start on level 4 + code:GANKLZPA + cheat + description:Start on level 5 + code:IANKLZPA + +cartridge sha256:fde81fc5af055819700842db8650077d64b853f95b3542bf12f039a6df48115d + title:Break Time - The National Pool Tour (USA) + cheat + description:Start in Milwaukee + code:VAVEILSA+PAVEGLAA + cheat + description:Start in Atlanta + code:VAVEILSA+ZAVEGLAA + cheat + description:Start in Los Angeles + code:VAVEILSA+LAVEGLAA + cheat + description:Start in Las Vegas + code:VAVEILSA+GAVEGLAA + +cartridge sha256:3bcce1ff03b55c20eeaefa44f35f19b3f06b3ff88a86ed51968bad9bd44d9144 + title:Bubble Bath Babes (USA) (Unl) + cheat + description:Infinite credits + code:SZEOLLVG + cheat + description:View slideshow + code:AAKAIAPE+VTXEXPSA+EAXEUPGV+GAUASOLE + +cartridge sha256:31523322db8f94e7244f6e2d958692a412c1395fc744601d83d1e5111eff9042 + title:Bubble Bobble (USA) + cheat + description:Skip only 2 levels + code:ZAOGOLGA + cheat + description:Skip 10 levels + code:ZAOGOLGE + cheat + description:Lots of bubble power + code:AAUILSPP + cheat + description:Monsters move faster + code:ZANEAGPA+NNEEAKVN + cheat + description:Monsters move super fast + code:LANEAGPA+NNEEAKSN + cheat + description:Angry monsters move faster + code:LANEIGZA+SNEEIKVN + cheat + description:Always wear turbo shoes + code:AANSIGTA+AESIPGTA + cheat + description:Start with 1 life - both players + code:PAUKEZLA + cheat + description:Start with 6 lives - both players + code:TAUKEZLA + cheat + description:Start with 9 lives - both players + code:PAUKEZLE + cheat + description:Start on level 10 + code:ZAUGEZPE + cheat + description:Start on level 25 + code:PPUGEZPE + cheat + description:Start on level 50 + code:ZLUGEZPA + cheat + description:Start on level 75 + code:LGUGEZPE + cheat + description:Invincibility - P1 + code:003F:2F + cheat + description:Invincibility - P2 + code:0053:2F + cheat + description:Infinite lives - P1 + code:002E:09 + cheat + description:Infinite lives - P2 + code:0042:09 + cheat + description:Float + code:0032:0A + cheat + description:Have Long Shot + code:0030:02 + cheat + description:Have Rapid Shot + code:0030:04 + cheat + description:Have Long and Rapid Shot + code:0030:06 + cheat + description:Have Lightning Shot + code:0030:45 + +cartridge sha256:d02b24e4ee8e639bf77af6746d6b3a92e996c0d2298861071851e2beec0ef812 + title:Bucky O'Hare (USA) + cheat + description:Infinite lives + code:SZVKOTVG + cheat + description:Hit anywhere + code:GXOEZTEL+GZNEYTEL+OXEAGVPV+OXOEYVPV + cheat + description:One hit kills + code:SLKSVUSO + cheat + description:Multi-jump + code:AEUEOYEL+AEXAUYAP + cheat + description:Double Bucky's special health + code:EPELVNKE + cheat + description:Triple Bucky's special health + code:KZELVNKA + cheat + description:All characters always selectable + code:ENKEVGAP + cheat + description:All characters start with normal special health + code:KAEUXNGE + cheat + description:All characters start with 2x special health + code:EPEUXNGE + cheat + description:All characters start with 3x special health + code:KZEUXNGA + cheat + description:1 life after continue + code:AEXGVYZA + cheat + description:6 lives after continue + code:IEXGVYZA + cheat + description:10 lives after continue + code:PEXGVYZE + cheat + description:Press Start to complete the level + code:AESGILPE+AESKALPA+GOSGYUPE+OXSGGUPK + cheat + description:Start a new game to see ending + code:PEUKEIZE + cheat + description:Start with 1/2 health + code:TAOLKYGP + cheat + description:Start with 1 life + code:AAELXYZA + cheat + description:Start with 6 lives + code:IAELXYZA + cheat + description:Start with 10 lives + code:PAELXYZE + cheat + description:Infinite health - all characters + code:05A0:14 + cheat + description:Infinite lives - all characters + code:004C:09 + cheat + description:Play as Jenny + code:0034:01 + cheat + description:Play as Dead Eye + code:0034:02 + cheat + description:Play as Blinky + code:0034:03 + cheat + description:Play as Willy DuWitt + code:0034:04 + +cartridge sha256:f01fe9436ca7b50953dbe5b8dd3574612df0e5df1fa9ae50d3f3b5faac818ab2 + title:Bugs Bunny Birthday Blowout, The (USA) + cheat + description:Invincibility + code:ATYZPL + cheat + description:Infinite health + code:SXEZGUSE + cheat + description:Infinite lives + code:SZVIGKVK + cheat + description:Mega-jumping Bugs + code:LAOANZTE + cheat + description:Two hearts of energy gained on pick-up + code:AEOXPZGE + cheat + description:Less energy gained on pick-up + code:PEOXPZGA + cheat + description:Stunned for longer + code:ATNZALAL + cheat + description:Stunned for less time + code:IPNZALAL + cheat + description:Use hammer when stunned + code:AASAKOTL + +cartridge sha256:7882e99e08deb1c22a3c38b17e12bd6373af503fd76e97b31699f3d19bef5aad + title:Bugs Bunny Crazy Castle, The (USA) + cheat + description:Invincibility + code:GXETZZEI + cheat + description:Baddies go as fast as Bugs Bunny + code:GXKGZZEY + cheat + description:Make platforms invisible + code:GASGAAPA + cheat + description:Start with super rabbit punches + code:PXXTGGEN+PXXTAGAO + cheat + description:Start with infinite lives + code:SZOKGPVG + cheat + description:Start with 1 life + code:PAUGPAIA + cheat + description:Start with 10 lives + code:ZAUGPAIE + cheat + description:Start on level 10 + code:SZOKGAAX+PEXYVYAE + cheat + description:Start on level 20 + code:SZOKGAAX+LOXYVYAA + cheat + description:Start on level 30 + code:SZOKGAAX+IOXYVYAE + cheat + description:Start on level 40 + code:SZOKGAAX+YXXYVYAA + +cartridge sha256:6f37316bbfec539809a946f7020e7a411fe5dbe204157522f01b9c616e918247 + title:Bugs Bunny Fun House (USA) (Beta) + cheat + description:Infinite turns + code:SXNKSKVK + cheat + description:Slower timer + code:EAXOLVGL + cheat + description:Faster timer + code:YPXOLVGU + cheat + description:Quicker turning + code:ZESXVGGA + cheat + description:More time from Large Glop Clocks + code:TOVOUEYE + cheat + description:Less time from Large Glop Clocks + code:YEVOUEYA + cheat + description:1 turn after continuing + code:PAXGSILA + cheat + description:9 turns after continuing + code:PAXGSILE + cheat + description:Start with 1 turn + code:PEOGXALA + cheat + description:Start with 9 turns + code:PEOGXALE + cheat + description:Start on Floor 2 + code:YEEKSAPA + cheat + description:Start on Floor 4 + code:LOEKSAPA + cheat + description:Start on Floor 6 + code:YOEKSAPE + cheat + description:Start on Floor 8 + code:LXEKSAPE + +cartridge sha256:ba8c9990f378b941ea362858509182b2b009e5b463e9732dc0071392b6253c2b + title:Bump'n'Jump (USA) + cheat + description:Jump OK, even with no power + code:AAVPNLGP + cheat + description:Gain double power on every pick-up + code:ZAUZAIPA + cheat + description:Jump OK at any speed + code:AGVONLAA + cheat + description:Set jump OK speed to 190 + code:PANPNLIE + cheat + description:Set jump OK speed to 130 + code:LANPNLIA + cheat + description:Start on scene 5 + code:GEOAGGAA + cheat + description:Start on scene 10 + code:PEOAGGAE + cheat + description:Start on scene 15 + code:TEOAGGAE + +cartridge sha256:abbddcb7c85a9956f94e6185aa1f30c34c45ad0db2f7f9db40066d749ffa7920 + title:Burai Fighter (USA) + cheat + description:Infinite lives + code:VNOTENVK + cheat + description:Extra lives for Eagle level + code:PEOLATIE + cheat + description:Extra lives for Albatross level + code:AEOLPTGE + cheat + description:Extra lives for Ace level + code:TEOLZTLA + cheat + description:More power for weapons + code:LAXTTPPA + cheat + description:Maximum power for weapons + code:ZAXTTPPE + cheat + description:Increase cobalt power picked up + code:PASVTPZE + cheat + description:Never lose weapon power + code:OUVNAXOO + cheat + description:Never lose speed up + code:KXNYLZSA + cheat + description:Never lose weapons + code:KXVNYZSA + cheat + description:Never lose rotating pod + code:KXNYPZSA + cheat + description:Never lose anything + code:AVVNLXOZ + cheat + description:Start with laser + code:VTVNIPSA + cheat + description:Start with rotating pod + code:VTNYPPSA + +cartridge sha256:8f349b0ed7d31a07ccdf26958de8219165eff7c9ad43801a82c5dcf831fd82c2 + title:BurgerTime (USA) + cheat + description:Anti-gravity shoes + code:GZVIAZEI + cheat + description:Peter Pepper gets super speed + code:YPESOUGO + cheat + description:Fast play for experts + code:SZKNNIAX + cheat + description:Monsters always move slowly + code:SXVSSXSU + cheat + description:Monsters move at double speed + code:SXVSSXSU+GOVSVXAO + cheat + description:Monsters move at quadruple speed + code:SXVSSXSU+YOVSVXAO + cheat + description:Start with infinite lives + code:SZSTVAVI + cheat + description:Start with 8 lives + code:AASGKLGE + cheat + description:Start with infinite peppers + code:SLKIZYVI + cheat + description:Start with double peppers + code:APVGSLIA + +cartridge sha256:2b4ac20082e2f45a8f8fd4922a0e995829719a523e118a9eec891c3206adf25b + title:B-Wings (Japan) + cheat + description:Invincibility + code:SAUXGISZ + cheat + description:Infinite lives + code:SLNZUSVK + cheat + description:Enable unlimited morphs + code:ASEUZLEY + cheat + description:Enable secret weapons morph + code:TEOLYULE + cheat + description:Can always morph + code:GXEUZLAI + cheat + description:Start with secret weapon 1 + code:LENUGAPE + cheat + description:Start with secret weapon 2 + code:IENUGAPE + +cartridge sha256:47dfae941b3c660be476bc28f199474b6c418431e3d493da4384a6aef3cc5016 + title:Cabal (USA) + cheat + description:Invincibility + code:ENNOLGEI + cheat + description:Infinite lives + code:GXEOZZVI + cheat + description:Infinite lives (alt) + code:SSEOZZVI + cheat + description:Infinite grenades + code:AEUXSIPA + cheat + description:Shorter immunity + code:AKOPLZEG + cheat + description:Longer immunity + code:NNOPLLEK + cheat + description:12 Grenades on pick-up + code:GAVXNGGE + cheat + description:2 Grenades on pick-up + code:ZAVXNGGA + cheat + description:Start with 20 grenades + code:KYVEOZUY + cheat + description:Start with 50 grenades + code:NYVEOZUY + cheat + description:Start with 9 lives - both players + code:UNUOTTNN + cheat + description:Start with 1 life - both players + code:UNUOTTNY + cheat + description:Invincibility - P1 + code:009F:02 + cheat + description:Invincibility - P2 + code:00A0:01 + cheat + description:Infinite Grenades - P1 + code:00D7:09 + cheat + description:Infinite Grenades - P2 + code:00D8:FB+00D9:FB + +cartridge sha256:85da8656317bb939de111a036132ccf358259bab29cf2e4fc694bbef4e55fff0 + title:California Raisins - The Grape Escape (USA) (Proto1) + cheat + description:Infinite health + code:SZXIKPVG + cheat + description:Infinite health (alt) + code:0048:04 + cheat + description:Infinite lives + code:0049:02 + +cartridge sha256:9ea5bedef90810b89afb70db90c6e0338aa2a6976603058dafe08838009651f0 + title:California Raisins - The Grape Escape (USA) (Proto2) + cheat + description:Invincibility + code:EIXSTPEY + cheat + description:Infinite lives + code:SKEKOTVG + cheat + description:Invincibility (blinking) + code:004D:FF + cheat + description:Infinite health + code:004A:04 + cheat + description:Infinite lives (alt) + code:004B:03 + +cartridge sha256:4ec881462687e08433605516d28624c5d9a7f33a243c64989c957adff8e0432a + title:Capcom's Gold Medal Challenge '92 (USA) + cheat + description:Massive run power + code:OXSYZVON+ASSYLTEY+XVSYGTVN + +cartridge sha256:6d694349435603c0dcd7645081b0761e109f3994b30f9d822586c991d93510d8 + title:Captain America and the Avengers (USA) + cheat + description:Infinite life - Captain America and Hawkeye, 1P mode + code:OLNUNEOO + cheat + description:Infinite continues + code:SZSULYVG + cheat + description:Large power stones worth 20 points + code:GPNXIUZA + cheat + description:Large power stones worth 30 points + code:TPNXIUZE + cheat + description:Large power stones worth 50 points + code:ZLNXIUZA + cheat + description:Small power stones worth 10 points + code:ZAUZILPE + cheat + description:Hawkeye shoots arrows faster + code:LSUPUELO + cheat + description:Faster Captain America and Hawkeye - one direction only + code:VYNXTXNN+ZEEZAZPA + cheat + description:Even faster Captain America and Hawkeye - one direction only + code:SYNXTXNN+LEEZAZPA + cheat + description:Ininite life - Captain America, 1P mode + code:03D9:0F + cheat + description:Infinite life - Hawkeye, 1P mode + code:03DA:0F + cheat + description:Have 99 Red Gems - Captain America, 1P mode + code:03DD:63 + cheat + description:Have 99 Red Gems - Hawkeye, 1P mode + code:03DE:63 + +cartridge sha256:935aa637ca8fb0ec4e0f3f09881c46c134b9a5821707e35899d8a7eedb17c6c3 + title:Captain Comic - The Adventure (USA) (Unl) + cheat + description:Invincibility + code:SZATEK + cheat + description:Infinite energy + code:SLATVK + cheat + description:Infinite lives + code:SZATZN + cheat + description:Max blast level + code:0316:09 + cheat + description:Infinite blast meter + code:0318:80 + cheat + description:Have Door Key + code:05AA:01 + cheat + description:Have Corkscrew + code:05AB:01 + cheat + description:Have Power Boots + code:05AC:01 + cheat + description:Have Teleport Wand + code:05B3:01 + cheat + description:Have Lantern + code:05B4:01 + cheat + description:Have Mystical Gems of Lascorbanos + code:05B5:01 + cheat + description:Have Coins of Tenure + code:05B6:01 + cheat + description:Have Crown of the Ages + code:05B7:01 + +cartridge sha256:41dd396fbd9b0883b4222b6fbdae09d0e3894eb015e965a0d228f21edd98ad8c + title:Captain Planet and the Planeteers (USA) + cheat + description:Invincibility + code:SZNKNUSE + cheat + description:Infinite lives (alt) + code:SKNLYVVK + cheat + description:Infinite lives, outside levels + code:SXNLYVVK + cheat + description:Infinite lives, inside levels + code:SZSUGVVK + cheat + description:Infinite power, outside levels + code:SZNXGXVK+SZVXPKVK + cheat + description:Infinite power, inside levels + code:SXXXEUVK+SZEUGKVK + cheat + description:Start with 2 lives instead of 5, outside levels + code:PENVIGGA + cheat + description:Start with 10 lives, outside levels + code:PENVIGGE + cheat + description:Start with 10 lives, inside levels + code:PAETITGE + cheat + description:Start with 2 lives, inside levels + code:PAETITGA + cheat + description:Start inside level 1 instead of outside. + code:AANVAEGZ + +cartridge sha256:da7886920245b1342185ed5fb963798dc38f96e8c5186b9c23446ef68c58a248 + title:Captain Skyhawk (USA) (Rev A) + cheat + description:Infinite lives + code:OZKAIGVK + cheat + description:Infinite lives (alt) + code:SGKAIGVG + cheat + description:Infinite Maverick missiles + code:OZXPUZVK + cheat + description:Infinite Hawk Bombs + code:OXKPVGVK + cheat + description:Double cost of Hawk Bombs + code:GENXKGZA + cheat + description:Double cost of Phoenix missiles + code:GAXZKIZA + cheat + description:Double cost of Maverick missiles + code:ZAOZEIIE + cheat + description:Start with half Hawk Bombs + code:LESITITA + cheat + description:Start with 20 Hawk Bombs + code:GOSITITA + cheat + description:Start with 8 Phoenix and Maverick missiles + code:AESSZIZE + cheat + description:Start with 1 life + code:PEUITIIA + cheat + description:Start with 10 lives + code:ZEUITIIE + +cartridge sha256:141cda262aad72971c00dd9a9655f32cee03e259d371bd8937a864e3300e9e58 + title:Captain Skyhawk (USA) + cheat + description:Invincibility (PRG0) + code:ESOOVIEY + cheat + description:Infinite lives + code:OZKAIGVK + cheat + description:Infinite lives (alt) + code:SGKAIGVG + cheat + description:Infinite Maverick missiles + code:OZXPUZVK + cheat + description:Infinite Hawk Bombs + code:OXKPVGVK + cheat + description:Double cost of Hawk Bombs + code:GENXKGZA + cheat + description:Double cost of Phoenix missiles + code:GAXZKIZA + cheat + description:Double cost of Maverick missiles + code:ZAOZEIIE + cheat + description:Start with half Hawk Bombs + code:LESITITA + cheat + description:Start with 20 Hawk Bombs + code:GOSITITA + cheat + description:Start with 8 Phoenix and Maverick missiles + code:AESSZIZE + cheat + description:Start with 1 life + code:PEUITIIA + cheat + description:Start with 10 lives + code:ZEUITIIE + +cartridge sha256:f76f1779454a8a98168c2c26bc79058161cbaefb3006c8e6aa8c63d301a66f4f + title:Casino Kid (USA) + cheat + description:Always win hand in Blackjack + code:OXKEPTES + cheat + description:Always win hand in Poker + code:SZOOUKGK + cheat + description:Can always bet all money in Blackjack + code:OXOEIIEO + cheat + description:Can always bet all money in Poker + code:VAVAKXAT + +cartridge sha256:87e479b14421fc4b56553937dc817789ebfb2987b0724c6790705f0361a955a7 + title:Casino Kid II (USA) + cheat + description:Can't double down in blackjack (game will say you do not have enough money) + code:PAOASGIE + cheat + description:Can't split in blackjack (game will say you do not have enough money) + code:PAKAVIIE + cheat + description:Start new game with $82 instead of $200 + code:AZKKYOTG + cheat + description:Start new game with $512 + code:EGKKYOTK + cheat + description:Start new game with $21,171 + code:AZSGGPAA + cheat + description:Start new game with $131,272 + code:EGSGGPAE + cheat + description:Start new game with $1,342,377 + code:AASKPPAE + cheat + description:Start new game with $5,368,909 + code:AZSKPPAA + +cartridge sha256:98ba2353111a0b2cf557b03d8b8c4f5c15d7be56e47182536d710913d62582fa + title:Castelian (USA) + cheat + description:Invincibility + code:SXKTEISA + cheat + description:Infinite lives + code:SLOKZLVI + cheat + description:Infinite lives (alt) + code:SIOKZLVI + cheat + description:Infinite time + code:SZNXYAVG + cheat + description:Start with 1 life + code:PEVGYPLA + cheat + description:Start with 6 lives + code:TEVGYPLA + cheat + description:Start with 9 lives + code:PEVGYPLE + cheat + description:Start with 5 continues + code:IAOGTZZA + cheat + description:Start with 8 continues + code:AAOGTZZE + +cartridge sha256:3668454e1904ada7f80ec2f94c4c2d45272d8a8c9e8d3b78ceebae5f890eb164 + title:Castle of Deceit (USA) (Unl) + cheat + description:Infinite energy + code:SXNIOUVK + cheat + description:Infinite lives + code:SZOSYSVK + +cartridge sha256:6887230077d8eefa311d313672c31e7497211e21c5df78aa8d2030ea72471108 + title:Castle of Dragon (USA) + cheat + description:Infinite health + code:YNOLSYAE + cheat + description:Super health + code:NYXKLAGE + cheat + description:No harm from most enemy attacks + code:SZVUSNVK + cheat + description:Stop Skeletons from fighting + code:PEVPULAP + cheat + description:Faster fighting + code:GEOGYZPA + cheat + description:Super strong enemies + code:ZPSLONLP + cheat + description:Start with Knives + code:ZAXGLAAA + cheat + description:Start with Knives and Mace + code:LAXGLAAA + cheat + description:Start with Armor + code:EAXGLAAA + cheat + description:Start with Armor, Knives and Mace + code:UAXGLAAA + +cartridge sha256:9abebd837287a38ab64153ff662b3bd79ebc8e55b07c2fc2fef8c15244517576 + title:Castlequest (USA) + cheat + description:Invincibility + code:SXUEXSSE + cheat + description:Infinite lives + code:SXKAVIVG + cheat + description:Infinite keys + code:ATSXATEY + cheat + description:75 lives instead of 50 + code:LKUZTZZU + cheat + description:25 lives instead of 50 + code:POUZTZZU + cheat + description:Don't lose life from 'reset' or 'back' options + code:SXKNKLVG + cheat + description:Use sword (press 'B') as long as you like + code:SZOEIUVK + cheat + description:Now you can move while using sword + code:XXOAZGYA + cheat + description:Must use with the last code for permanent sword-wielding ability + code:IAEEALYP + cheat + description:Supercharged speed-up + code:GAXEGIZA+GAUEGIZA + cheat + description:Turbo fuel-injected 16-valve speed-up + code:AAXEGIZE+AAUEGIZE + +cartridge sha256:7eba1637cd2fdbc4f0732eb5249e32d827dbdadbd7e165f961440af4310880dc + title:Castlevania (USA) (Rev A) + cheat + description:Invincibility + code:SKSTZTSZ + cheat + description:Invincibility after one hit + code:VXNVXAVG + cheat + description:Infinite lives + code:OXNGLZVK + cheat + description:Infinite time + code:SXXXYAAX + cheat + description:Infinite hearts + code:KZSSEZKA+KXESUZKA + cheat + description:Keep weapons after losing a life + code:GZOGYUSE + cheat + description:Gain triple shot on weapon pick-up + code:ZEUTAYAA + cheat + description:Don't get knocked back when hit + code:NAPOLN + cheat + description:Jump 3x as high + code:SKPPEL + cheat + description:Jump 2x as high + code:EVPPEL + cheat + description:Multi-jump + code:AVOPZYEP+VEEOGGSV+KOEOIGOZ+OZOOIKSE+PAOOTGLG+SAOOYGPE+GTXPAKVV+GAXPPKGT+ZGXPZGGE+AXKOZKSZ+PEKOLGGP+KOKOGGIA + cheat + description:Start with 40 hearts + code:AXOGOPIE + cheat + description:Start with 80 hearts + code:ASOGOPIA + cheat + description:Start with 1 life + code:PANKXPGA+PANGSAGA + cheat + description:Start with 8 lives + code:AANKXPGE+AANGSAGE + cheat + description:Start on last level + code:VXOLEOVE+PEEUEPLE+ZOEUSPAA + cheat + description:Invincibility (blinking) + code:005B:02 + cheat + description:Infinite health + code:0045:40 + cheat + description:Infinite lives (alt) + code:002A:63 + cheat + description:Infinite hearts (alt) (disable at end of stage) + code:0071:63 + cheat + description:Bosses have no health + code:01A9:00 + cheat + description:Have the Axe + code:015B:0D + cheat + description:Have the Cross + code:015B:09 + cheat + description:Have the Holy Water + code:015B:0B + cheat + description:Have the Knife + code:015B:08 + cheat + description:Have the Stopwatch + code:015B:0F + cheat + description:Have the best whip + code:0070:02 + +cartridge sha256:a35e846379ff252594ace83da2a1a1cb0692717b931055d1f6603812f18ad5cd + title:Castlevania (USA) + cheat + description:Infinite time + code:SXXXYAAX + cheat + description:Hit anywhere (Whip) + code:AAOVLSVG+AAXVLSVL + cheat + description:Jump 3x as high + code:SKPPEL + cheat + description:Jump 2x as high + code:EVPPEL + cheat + description:Multi-jump + code:AVOPZYEP+VEEOGGSV+KOEOIGOZ+OZOOIKSE+PAOOTGLG+SAOOYGPE+GTXPAKVV+GAXPPKGT+ZGXPZGGE+AXKOZKSZ+PEKOLGGP+KOKOGGIA + cheat + description:Start on last level + code:VXOLEOVE+PEEUEPLE+ZOEUSPAA + cheat + description:Invincibility (blinking) + code:005B:02 + cheat + description:Infinite health + code:0045:40 + cheat + description:Infinite lives + code:002A:63 + cheat + description:Infinite hearts + code:0071:63 + cheat + description:Bosses have no health + code:01A9:00 + cheat + description:Have the Axe + code:015B:0D + cheat + description:Have the Cross + code:015B:09 + cheat + description:Have the Holy Water + code:015B:0B + cheat + description:Have the Knife + code:015B:08 + cheat + description:Have the Stopwatch + code:015B:0F + cheat + description:Have the best whip + code:0070:02 + +cartridge sha256:9575ec31c1c658fd6b77ae1d69e4861ecada8570e4eebf51409941486e4b4ef4 + title:Castlevania II - Simon's Quest (USA) + cheat + description:Infinite health + code:SZSSYLSA + cheat + description:Infinite lives + code:GXOGGZVG + cheat + description:Infinite Laurels + code:IAXIOPVG + cheat + description:Infinite Garlic + code:SZUISPVG + cheat + description:Always daytime + code:SXOSLYSA + cheat + description:Small hearts worth 100 + code:KATAZY + cheat + description:Multi-jump + code:VVSEVOSV+XVSEKPEN+EESEOPAP+ESSEXPLP+GESEUPEX+GKSESPAX+OESENPVE+PXSEEPLE+SNSANOGT+SXSAVOSZ+UNVEOPAE + cheat + description:Whip can destroy any block + code:AALSPT+AAZSAT+APISIT+XVPIPV + cheat + description:Whip destroys all enemies/townspeople on screen + code:INIEEA + cheat + description:Start with 100 Experience (E) + code:PAZNGO + cheat + description:Start with more health + code:AISKTIAL + cheat + description:Start with 25 hearts + code:IZSKZIAI + cheat + description:Start with 75 hearts + code:IYSKZIAI + cheat + description:Start with 1 life + code:PASGLILA + cheat + description:Start with 6 lives + code:TASGLILA + cheat + description:Start with 9 lives + code:PASGLILE + cheat + description:Invincibility + code:04F8:02 + cheat + description:Infinite health (alt) + code:0080:50 + cheat + description:Infinite lives (alt) + code:0031:03 + cheat + description:Infinite hearts + code:0048:F0 + cheat + description:Infinite Laurels (alt) + code:004C:99 + cheat + description:Infinite Garlic on pick-up + code:004D:08 + cheat + description:Always daytime (alt) + code:0085:02 + cheat + description:Have all Daggers, Holy Water, Diamond, Flame and Oak Stake + code:004A:7F + cheat + description:Have White Crystal + code:0091:20 + cheat + description:Have all Dracula's parts and White Crystal + code:0091:3F + cheat + description:Have Blue Crystal + code:0091:40 + cheat + description:Have all Dracula's parts and Blue Crystal + code:0091:5F + cheat + description:Have Red Crystal + code:0091:60 + cheat + description:Have all Dracula's parts and Red Crystal + code:0091:7F + cheat + description:Have Garlic, Laurels, Silk Bag and Magic Cross + code:0092:0F + cheat + description:Have Fire Whip + code:0434:04 + +cartridge sha256:6e8d289635ac39479ff1d36733aa3f8b9650593ab972cedb8e2cdbfc03aaa739 + title:Castlevania III - Dracula's Curse (USA) + cheat + description:Invincibility (disable if you cannot enter a door) + code:EIOAZPEY + cheat + description:Invincibility (disable if you cannot enter a door) (alt) + code:SZKLPZSA + cheat + description:Infinite health + code:OXEEZZSE + cheat + description:Infinite lives + code:OXOAUPSE + cheat + description:Hit anywhere (Whip) + code:AEELYXAP + cheat + description:Multi-jump + code:SASOUESX+SASPVESX+SZSPOAGA+SZUPOASA+TZSPXEOG+ZASPUEAE+AVVAELAP+EISOKAIV+EPSPKAEL+IASONATZ+IASOXEGA+IAVPOEAA+OZSOOAES+PSSPINYG+PSVPYUYG + cheat + description:Start with 9500 seconds + code:PALUYL + cheat + description:Start each stage with 99 hearts + code:OOKPPAIE + cheat + description:Invincibility (blinking) (disable if you cannot enter a door) + code:0080:02 + cheat + description:Remove invincibility blinking + code:001A:00 + cheat + description:Infinite health (alt) + code:003C:40 + cheat + description:Infinite lives (alt) + code:0035:99 + cheat + description:Infinite hearts + code:0084:99 + cheat + description:Trevor has best Whip + code:008E:02 + cheat + description:Alucard has best attack + code:008F:02 + cheat + description:Enable Sypha + code:003A:01 + cheat + description:Enable Grant + code:003A:02 + cheat + description:Enable Alucard + code:003A:03 + cheat + description:Trevor's sub-weapon - Axe + code:0085:01 + cheat + description:Trevor's sub-weapon - Cross + code:0085:02 + cheat + description:Trevor's sub-weapon - Dagger + code:0085:03 + cheat + description:Trevor's sub-weapon - Holy Water + code:0085:04 + cheat + description:Partner's sub-weapon - Fire Spell + code:0086:05 + cheat + description:Partner's sub-weapon - Ice Spell + code:0086:06 + cheat + description:Partner's sub-weapon - Lightning Spell + code:0086:07 + cheat + description:Partner's sub-weapon - Dagger + code:0086:08 + cheat + description:Partner's sub-weapon - Axe + code:0086:09 + cheat + description:Partner's sub-weapon - Clock + code:0086:0B + cheat + description:Start on stage 2 (glitchy if you die) + code:0032:01 + cheat + description:Start on stage 3 (glitchy if you die) + code:0032:02 + cheat + description:Start on stage 4 (glitchy if you die) + code:0032:03 + cheat + description:Start on stage 5 (glitchy if you die) + code:0032:04 + cheat + description:Start on stage 6 (glitchy if you die) + code:0032:05 + cheat + description:Start on stage 7 (glitchy if you die) + code:0032:06 + cheat + description:Start on stage 8 (glitchy if you die) + code:0032:07 + cheat + description:Start on stage 9 (glitchy if you die) + code:0032:08 + cheat + description:Start on stage 10 (glitchy if you die) + code:0032:09 + cheat + description:Start on stage 11 (glitchy if you die) + code:0032:0A + cheat + description:Start on stage 12 (glitchy if you die) + code:0032:0B + cheat + description:Start on stage 13 (glitchy if you die) + code:0032:0C + cheat + description:Start on stage 14 (glitchy if you die) + code:0032:0D + cheat + description:Start on stage 15 (glitchy if you die) + code:0032:0E + +cartridge sha256:c20a8cc1b2dacb8a45e706b5763ac6c82c17b4ee4fb547ba4a853e4aabd6e35c + title:Challenge of the Dragon (USA) (Unl) + cheat + description:Infinite health + code:SZSTZXSO + cheat + description:Infinite lives + code:OUOVZKOO + cheat + description:Always have Bombs + code:ASXTVGEI + +cartridge sha256:7f4b9307e228c737b5f6e4ef3efb40438aa2024b95b29f9aabf18a15af6ed185 + title:Challenge of the Dragon (Asia) (PAL) (Unl) + cheat + description:Invincibility + code:ATNXPAEY + cheat + description:Infinite health + code:SZXZAPVG + cheat + description:Infinite lives + code:OZOEXYVK + +cartridge sha256:d5b039637a2315458f71ec57a287f93b3532e6243b712b55767f07dc83c5a3c9 + title:Championship Pool (USA) + cheat + description:1 foul loses the game (instead of 3) - only in 10-ball in party mode + code:PAOUYALA + cheat + description:2 fouls in a row loses the game - only on 9 and 10-ball in party mode + code:ZAOUYALA + cheat + description:Fouls don't count - only on 9 and 10-ball and rotation in party mode + code:SLNUKXSO + cheat + description:Number of fouls is not cleared after a good shot (3 fouls don't have to be in a row to lose) - only on 10-ball in party mode + code:SUOLXXSO + cheat + description:Always break in 9 or 10-ball - P1 + code:OZVETASX+AAVEYEST + cheat + description:Always break in 9 or 10-ball - P2 + code:OZVETASX+PAVEYEST + +cartridge sha256:ebdd748cd488c4acdc5d2c7321de692c1ab0b37044cf0c6ea043457176dbd306 + title:Cheetahmen II (USA) (Unl) + cheat + description:Infinite health - level 1 and 2 + code:SXUXGUVK + cheat + description:Infinite health - level 3 + code:SXSXGUVK + cheat + description:Infinite health - level 4 + code:SXEZGUVK + cheat + description:Infinite lives - level 1 and 2 + code:SZNUAUVK + cheat + description:Infinite lives - level 3 + code:SZEUYUVK + cheat + description:Infinite lives - level 4 + code:SXXUIXVK + +cartridge sha256:e84d90fefb92f2b6ab70e35bfb990978c7e384e357ec6b995c3880bff4c5b460 + title:Chip 'n Dale - Rescue Rangers (USA) + cheat + description:Infinite health + code:AOEITEEN + cheat + description:Multi-jump + code:AAKGSGPA+SXXKEOZA + cheat + description:Freeze mechanical bulldog + code:ATUEENSL + cheat + description:Freeze mechanical mice + code:AVKAVNSL + cheat + description:Freeze buzzer + code:AVOPTESL + cheat + description:Freeze buzz bomb + code:AVNOLKSL + cheat + description:Freeze racket-rod + code:AVVPZSSL + cheat + description:Freeze ditz + code:ATSOYKSL + cheat + description:Freeze hawk bomber + code:ATSPANSL + cheat + description:Freeze bouncing boxes + code:AVVOOUSL + cheat + description:Mega-jump + code:ZEXKNPTE + cheat + description:Never get stunned + code:GAEIIEVI + cheat + description:Press Start to finish the level + code:IVEKINEO + +cartridge sha256:afa359b53e90781ed3810642c09f7cb22f0ba21c40142649771bfb21a897b4d3 + title:Chip 'n Dale - Rescue Rangers 2 (USA) + cheat + description:Invincibility (glitchy) + code:EIXZEZEY + cheat + description:Infinite health + code:SSXLLEVS + cheat + description:Infinite health - both players + code:OUXLLEVS + cheat + description:Infinite lives - both players + code:NXKZKTVI + cheat + description:Almost infinite lives - both players + code:GXKZKTVI + cheat + description:Infinite credits + code:OXUNGIVK + cheat + description:Never get stunned + code:XVXXXGVS + cheat + description:Start with 1 life - both players + code:PEUYIILA + cheat + description:Start with 2 lives - both players + code:ZEUYIILA + cheat + description:Start with 4 lives - both players + code:GEUYIILA + cheat + description:Start with 5 lives - both players + code:IEUYIILA + cheat + description:Start with 1 heart - both players + code:PEOYZILA + cheat + description:Start with 2 hearts - both players + code:ZEOYZILA + cheat + description:Start with 4 hearts - both players + code:GEOYZILA + cheat + description:Start with 5 hearts - both players + code:IEOYZILA + cheat + description:Start with 1 credit + code:PANNAILA + cheat + description:Start with 2 credits + code:ZANNAILA + cheat + description:Start with 6 credits + code:TANNAILA + cheat + description:Start with 9 credits + code:PANNAILE + cheat + description:Start with 255 credits (ignore the counter) + code:NYNNAILE + +cartridge sha256:21a7f7a5a043ddc2017cd97b4088156b0d728271455966ab6748a79eddd3410e + title:Chubby Cherub (USA) + cheat + description:Infinite lives + code:SZEAYZVG + cheat + description:Infinite power + code:SZEXIYSA + cheat + description:Half regular power gained from food + code:GEVAKVAA + cheat + description:Slow down power loss on the ground + code:PENXATZA + cheat + description:Slow down power loss in the air + code:LENXTVPA + cheat + description:Infinite Gau (shots) + code:ZANEVSUT + cheat + description:Double Gau (shots) on candy pick-up + code:AASXOAGE + cheat + description:Start with 1 life + code:AEOAAZZA + cheat + description:Start with double lives + code:IEOAAZZA + cheat + description:Start with triple lives + code:AEOAAZZE + cheat + description:Start on Stage 5 + code:IEOALZPA+GEOAPZAA + cheat + description:Start on Stage 10 + code:ZEOALZPE+PEOAPZAE + +cartridge sha256:fa701601d39819ef26821d05350ccb793cc606191e03c06203a4274b434dfaeb + title:Circus Caper (USA) + cheat + description:Invincibility in normal levels + code:SYNNPGLA+TANNAGZS+AZNYYKSZ + cheat + description:Infinite power (health) + code:GZEYPSSE + cheat + description:Infinite power (health) (alt) + code:SZEYPSSE + cheat + description:Full energy from food + code:AASVNAZA + cheat + description:Start with lots of weapons + code:NNOTNLAE + cheat + description:Start on stage 2 (starts on stage 1 after continuing) + code:ZEVGGAPA + cheat + description:Start on stage 3 (starts on stage 1 after continuing) + code:LEVGGAPA + cheat + description:Start on stage 4 (starts on stage 1 after continuing) + code:GEVGGAPA + cheat + description:Start on stage 5 (starts on stage 1 after continuing) + code:IEVGGAPA + cheat + description:Start on stage 6 (starts on stage 1 after continuing) + code:TEVGGAPA + cheat + description:Infinite power (health) (alt 2) + code:0392:7A + +cartridge sha256:590535e8cda84cb4054425539bc320c16307f141d688b57f258a162dedc8888f + title:City Connection (USA) + cheat + description:Infinite lives + code:SZNSTPVG + cheat + description:Infinite Oil + code:SXKPZGVG + cheat + description:Start with double lives + code:IEKEYIZA + cheat + description:Start with triple lives + code:AEKEYIZE + cheat + description:Start with extra Oil + code:AXSAPIIA + cheat + description:Start on level 1 + code:PEKEIIAA + cheat + description:Start on level 2 + code:ZEKEIIAA + cheat + description:Start on level 3 + code:LEKEIIAA + cheat + description:Start on level 4 + code:GEKEIIAA + cheat + description:Start on level 5 + code:IEKEIIAA + cheat + description:Infinite lives - both players + code:00A2:09 + cheat + description:Infinite Oil - both players + code:00A4:63 + cheat + description:MI is very high + code:00A5:FF + +cartridge sha256:cf226f0d9486103bbaa19ee124b673d47aa2b3766334b6b7587d704c03e6649e + title:Clash at Demonhead (USA) + cheat + description:Invincibility + code:ENOPLZEI+ESSPPAEY + cheat + description:Infinite health + code:SZEGZISA + cheat + description:Infinite barrier hits + code:SXNZKSVK + cheat + description:Infinite supply of all items bought + code:SXKZGSVS + cheat + description:Don't die when power hits zero + code:VZSULOVV + cheat + description:All items in shop are free + code:AVUGAGST + cheat + description:Start with 1 of each item + code:VNNGNUSO + cheat + description:Start with extra cash + code:TAUGKGKY+UPUGVKXO + cheat + description:Start with 50% power + code:AAEKVGAO+AEVZNPAO+ZAOGXGGA + cheat + description:Start with 150% power + code:APEKVGAO+TAOGXGGA+AOVZNPAO + cheat + description:Start with 200% power + code:AZEKVGAP+AAOGXGGE+AXVZNPAP + cheat + description:Infinite health (alt) + code:009F:10 + +cartridge sha256:79969ab6741823e5560794489d5b20a677a1207c06265855e5d7b633e6fef29a + title:Cliffhanger (USA) + cheat + description:Protection from most hits + code:SZVPOKVK + cheat + description:Infinite lives + code:SXEKKSVK + cheat + description:Infinite continues + code:ULOTSYTN + cheat + description:Don't burn money at campfire + code:SUNPXXSO + cheat + description:Some bags contain mega-money, some contain no money + code:YONKKXAP + cheat + description:Start with 2 lives + code:PASGVGLA + cheat + description:Start with 6 lives + code:IASGVGLA + cheat + description:Start with 8 lives + code:YASGVGLA + cheat + description:Start with 10 lives + code:PASGVGLE + cheat + description:Start with 1 continue + code:PAKGUGLA + cheat + description:Start with 5 continues + code:IAKGUGLA + cheat + description:Start with 7 continues + code:YAKGUGLA + cheat + description:Start with 9 continues + code:PAKGUGLE + cheat + description:Start with 2x health (does not show on meter) + code:AXOKNGAP + cheat + description:Start with 1/2 health + code:AEOKNGAO + cheat + description:Start with $100 + code:VTVKVKSE + cheat + description:Start with $10,000 + code:VTVKUKSE + cheat + description:Start with $650,000 (displays $xx0000 until you pick up first money bag) + code:VGVKUKSE + cheat + description:Infinite health + code:0405:10 + cheat + description:Infinite lives (alt) + code:0406:03 + +cartridge sha256:ed0a1a5ca7cf404116d0073e8ccd213a082d2ac50132f54f3c8621f3dbcdb248 + title:Clu Clu Land (World) + cheat + description:Infinite lives - both players + code:GXLILL + cheat + description:Infinite time + code:GZPGSL + cheat + description:Increase extra time + code:TEYIGL + cheat + description:Shoot more rays + code:IEVISZZA + cheat + description:Shoot shorter rays + code:AOVSOZAZ + cheat + description:Shoot longer rays + code:ASVSOZAZ + cheat + description:Enemy can go thru gold bars + code:AASIAYGA + cheat + description:Start with 1 life - both players + code:PAGKGL + cheat + description:Start with 10 lives - both players + code:APGKGL + cheat + description:Start with 1 life - P2 + code:VTSKPLSA + +cartridge sha256:711eee6690af76a59321f49c8dbfec39eef702775e6cc2a1e63553b40fa3aa5f + title:Cobra Command (USA) + cheat + description:Immune to weapon damage + code:GZSSNGST + cheat + description:Start with infinite lives + code:SXUAAOVK + cheat + description:Start with 1 life + code:AAUVGZGA + cheat + description:Start with 9 lives + code:AAUVGZGE + cheat + description:Start with Infinite lives (alt) + code:05BB:09 + cheat + description:Start with Dual Gun + code:05A5:01 + cheat + description:Start with ATG + code:05A5:02 + cheat + description:Start with Rapid Fire + code:05A5:03 + cheat + description:Start with 3-Way Gun + code:05A5:04 + cheat + description:Start with Twin Missiles + code:05A6:01 + cheat + description:Start with Homing Missiles + code:05A6:02 + cheat + description:Start with Homing Missiles 1 + code:05A6:03 + cheat + description:Start with Homing Missiles 2 + code:05A6:04 + cheat + description:Start with Firebomb + code:05A6:05 + cheat + description:Start with Mines + code:05A6:06 + cheat + description:Start with Armor + code:05A7:01 + cheat + description:Start with Super Armor + code:05A7:02 + cheat + description:Start with Hyper Armor + code:05A7:03 + cheat + description:Start with Turbo Engine + code:05A8:01 + cheat + description:Start with Super Engine + code:05A8:02 + cheat + description:Start with Hyper Engine + code:05A8:03 + cheat + description:Start with Rope + code:05A9:00 + cheat + description:Start with Ladder + code:05A9:01 + +cartridge sha256:db26936868427b5b01b7823a781ec09ed15bb5dd06945bba0147ffb12215234b + title:Cobra Triangle (USA) + cheat + description:Invincibility + code:ATVXKLEI + cheat + description:Infinite continue options + code:SZUXZVVK + cheat + description:Don't lose life after dying from damage + code:SZEVNOVK + cheat + description:Don't lose life after dying from time running out + code:SZVTSOVK + cheat + description:Never lose your power-ups + code:ENXTPVSA+LEXTZVAX + cheat + description:Hit anywhere + code:EIXLPGEL+ESKZXGEL+KPULZGNO+OLKXOSOO+TAXLZGZO+YOKZUKZP + cheat + description:Gain an extra minute + code:VVXEAUSE+LOXEPLIP + cheat + description:Invincibility (blinking) + code:00B9:1A + cheat + description:Infinite health + code:05F5:0C + cheat + description:Infinite lives + code:0738:09 + cheat + description:Infinite time (disable before finishing a level) + code:0714:05 + cheat + description:Boss HP will be at minimum + code:05FF:00 + cheat + description:Max Missile power + code:072C:03 + cheat + description:Max Speed + code:072B:03 + cheat + description:One 1 mine needed for mine removing stages + code:00A3:00 + cheat + description:Start on stage 2 (disable after stage begins) + code:0702:02+0737:01 + cheat + description:Start on stage 3 (disable after stage begins) + code:0702:03+0737:02 + cheat + description:Start on stage 4 (disable after stage begins) + code:0702:04+0737:03 + cheat + description:Start on stage 5 (disable after stage begins) + code:0702:05+0737:04 + cheat + description:Start on stage 6 (disable after stage begins) + code:0702:06+0737:05 + cheat + description:Start on stage 7 (disable after stage begins) + code:0702:07+0737:06 + cheat + description:Start on stage 8 (disable after stage begins) + code:0702:08+0737:07 + cheat + description:Start on stage 9 (disable after stage begins) + code:0702:09+0737:08 + cheat + description:Start on stage 10 (disable after stage begins) + code:0702:0A+0737:09 + cheat + description:Start on stage 11 (disable after stage begins) + code:0702:0B+0737:0A + cheat + description:Start on stage 12 (disable after stage begins) + code:0702:0C+0737:0B + cheat + description:Start on stage 13 (disable after stage begins) + code:0702:0D+0737:0C + cheat + description:Start on stage 14 (disable after stage begins) + code:0702:0E+0737:0D + cheat + description:Start on stage 15 (disable after stage begins) + code:0702:0F+0737:0E + cheat + description:Start on stage 16 (disable after stage begins) + code:0702:10+0737:0F + cheat + description:Start on stage 17 (disable after stage begins) + code:0702:11+0737:10 + cheat + description:Start on stage 18 (disable after stage begins) + code:0702:12+0737:11 + cheat + description:Start on stage 19 (disable after stage begins) + code:0702:13+0737:12 + cheat + description:Start on stage 20 (disable after stage begins) + code:0702:14+0737:13 + cheat + description:Start on stage 21 (disable after stage begins) + code:0702:15+0737:14 + cheat + description:Start on stage 22 (disable after stage begins) + code:0702:16+0737:15 + cheat + description:Start on stage 23 (disable after stage begins) + code:0702:17+0737:16 + cheat + description:Start on stage 24 (disable after stage begins) + code:0702:18+0737:17 + cheat + description:Start on stage 25 (disable after stage begins) + code:0702:19+0737:18 + +cartridge sha256:2be0bd6e64cf2cb47c7b4a2d6bdb5fd4ff9ed1cd5eb6eadb4d56c410c659bdc5 + title:Code Name - Viper (USA) + cheat + description:Invincibility + code:SZSSGIAX + cheat + description:Infinite health + code:STVPVOON+AASOVZPA + cheat + description:Infinite health (alt) + code:SZVOSOSE + cheat + description:Infinite lives + code:SZOVKNVK + cheat + description:Infinite Gun + code:AENXZPPA + cheat + description:Infinite Machine Gun + code:AAOXLZPA + cheat + description:Hit anywhere + code:AASIVEAL+APOOSGLA+GLXPEGLP+SZOOKKSU + cheat + description:Double usual bullets on new life + code:GTOVEYZL + cheat + description:Half bullets on new life + code:PPOVEYZU + cheat + description:Machine Gun with 256 bullets on new life + code:VTOTONSE + cheat + description:Upper level jump + code:SXKEVNOU+ONEOYEXN + cheat + description:Keep Machine Gun after dying + code:GZOTONSE+GZEVVNSE + cheat + description:Have Bomb (can exit level without the Bomb) + code:AEESIIGA + cheat + description:Start with 1 life + code:PENTAGLA + cheat + description:Start with 6 lives + code:TENTAGLA + cheat + description:Start with 9 lives + code:PENTAGLE + cheat + description:Start with Machine Gun and 256 bullets + code:VVNVGKSE + cheat + description:Start with double usual bullets + code:GTETLIZL + cheat + description:Start with half usual bullets + code:PPETLIZU + cheat + description:Infinite health (alt) + code:06F8:04 + cheat + description:Infinite lives + code:06E8:0A + cheat + description:Infinite Gun (alt) + code:06E0:3F + cheat + description:Infinite Machine Gun (alt) + code:06E2:3F + cheat + description:Have all children rescued + code:06EA:09 + cheat + description:Have all adults rescued + code:06EC:09 + cheat + description:Have all adults and children rescued + code:0757:FF + +cartridge sha256:47ebed8be6679468d0627065153520a539b292244b51c54263c027e106b6ef65 + title:Colorful Dragon (Asia) (PAL) (Unl) + cheat + description:Invincibility + code:EIEPXZEY + cheat + description:Infinite lives + code:SUUOKPVI + cheat + description:Start on level 2 + code:ZAUAYAPA + cheat + description:Start on level 5 + code:IAUAYAPA + cheat + description:Start on level 10 + code:ZAUAYAPE + cheat + description:Start on level 15 + code:YAUAYAPE + cheat + description:Start on level 20 + code:GPUAYAPA + +cartridge sha256:0512b4aa2220f74e40fe8652b758893fa87efb6c3407808f7dda0e1901017432 + title:Commando (USA) + cheat + description:Invincibility + code:ATNITPSA + cheat + description:Infinite Grenades + code:XVULASXK + cheat + description:Infinite lives + code:EZEGNOVG + cheat + description:Infinite lives (alt) + code:SZEGNOVK + cheat + description:Start with 1 life - both players + code:AEKKIILA + cheat + description:Start with 6 lives - both players + code:TEKKIILA + cheat + description:Start with 9 lives - both players + code:PEKKIILE + cheat + description:Start with double rations of grenades + code:AOSGIIIA + cheat + description:Have all power-ups - both players + code:04AB:E9 + cheat + description:Have rapid fire - both players + code:0074:00 + +cartridge sha256:8ae9b624c08b86f6af41b5d58c328188c6df9c35868ae0763d75a22fbfb6c712 + title:Conan (USA) + cheat + description:Invincibility + code:SXUEYYAX+SZVAPGAX + cheat + description:Infinite lives + code:SXKISTVG+SZVSULVG + cheat + description:Infinite health + code:SXSTOOSE + +cartridge sha256:a5b8e24589539b0b84a6ad98aee9c91eb86eff795162be38b020dc42c3e3eca7 + title:Conquest of the Crystal Palace (USA) + cheat + description:Invincibility + code:ESVIYPEY+SEVIIPSZ + cheat + description:Invincibility (alt) + code:SXOVLIAX + cheat + description:Infinite lives + code:GZVTAPAX + cheat + description:Infinite lives (alt) + code:SZVTLPSA + cheat + description:Infinite energy (will display wrong info) + code:VVKSZOSU + cheat + description:Infinite energy for Farron + code:SXXTAIAX + cheat + description:Infinite fire power + code:SUPILU + cheat + description:Maximum energy without Life Crystal + code:GPEYUXTA + cheat + description:Don't use up money when buying things + code:GZXVPPAX+GZUTZPAX + cheat + description:Super-jump without Flight Crystal + code:AAVIGTZA+PAVITTLA + cheat + description:Increase super-jump to mega-jump + code:IOUSLVTA + cheat + description:Increase super-jump to super-mega-jump + code:IKUSLVTA + +cartridge sha256:62c9d4e0578cb1e615ce9bb2c8ebc15b1e8de4c928c5c07ba9a85c11aa36ae4d + title:Contra (Japan) + cheat + description:Invincibility + code:SXNVZPAX + cheat + description:Infinite lives + code:SZUSOPVI + +cartridge sha256:d41e28b1a33b3b6768e7c39c9fdfb1fda4b49940542d14085911fabd399e1ca9 + title:Contra (USA) + cheat + description:Invincibility + code:SXKVPZAX + cheat + description:Invincibility (blinking) + code:SLTIYG + cheat + description:Invincibility (blinking) (alt) + code:AAVITGIA + cheat + description:Hit anywhere + code:ESEVALEP+GXXTPLEL+GZNVYLEL+SXKTYLAX + cheat + description:Multi-jump - both players + code:AZNITGSL+NPNIYGEU+VINSAGEY+XTNSPKAE+SUEIAGVI+SUVSOPSP+ATKSZSOZ + cheat + description:Jump higher + code:UNVSYVKN+XNVSPVUN + cheat + description:Run 2x as fast + code:VYVIPNNN+ZASSIYPA + cheat + description:Run 4x as fast + code:GASSIYPA+KYVIPNNN + cheat + description:Keep weapons after losing life + code:GXIIUX + cheat + description:Press Select to change weapons - P1 + code:GGXNIVNN+IZOYLVNY+KZOYZVNY+PZONYVNN+LAOYIVNY+SAXNPVNY+LIOYYVNY+SZXNLVNY+OGXYPVNN+YAXYAVNY+SYXNGVNY+OZXYIVNN+ZAXYGVNY+SZONIVNY+PAXNAVNY+ZPKILAIZ+TAONGVNN+PTXYYVNN+TGXNTVNY+PZONPVNN+VYKIGAEI+XZONTVNN+XZXNZVNN+AZONZVNY+EIONAVNY+EIXNYVNY+EIXYLVNY+EYONLVNY+EYOYGVNY+GAXYZVNY+GGKIZAKX+GGOYTVNN + cheat + description:Press Start to complete the level + code:LLKSIAIX + cheat + description:Start with infinite lives + code:SLAIUZ + cheat + description:Start new life with Machine Gun + code:PEIIXZ + cheat + description:Start new life with Fireball + code:ZEIIXZ + cheat + description:Start new life with Spread Gun + code:LEIIXZ + cheat + description:Start new life with Laser + code:GEIIXZ + cheat + description:Start on level 2 + code:ALNKPKYL+PANGIGAA + cheat + description:Start on level 3 + code:ALNKPKYL+ZANGIGAA + cheat + description:Start on level 4 + code:ALNKPKYL+LANGIGAA + cheat + description:Start on level 5 + code:ALNKPKYL+GANGIGAA + cheat + description:Start on level 6 + code:ALNKPKYL+IANGIGAA + cheat + description:Start on level 7 + code:ALNKPKYL+TANGIGAA + cheat + description:Start on level 8 + code:ALNKPKYL+YANGIGAA + cheat + description:Invincibility (star effect) - P1 + code:00B0:FE + cheat + description:Invincibility (star effect) - P2 + code:00B1:FE + cheat + description:Invincibility (blinking) (alt 2) + code:00AE:41 + cheat + description:Have 99 lives + code:0032:99 + cheat + description:Have Machine Gun - P1 + code:00AA:01 + cheat + description:Have Fireball - P1 + code:00AA:02 + cheat + description:Have Spread Gun - P1 + code:00AA:03 + cheat + description:Have Laser - P1 + code:00AA:04 + cheat + description:Have Clone Attack (glitch weapon) - P1 + code:00AA:18 + cheat + description:Have Machine Gun - P2 + code:00AB:01 + cheat + description:Have Fireball - P2 + code:00AB:02 + cheat + description:Have Spread Gun - P2 + code:00AB:03 + cheat + description:Have Laser - P2 + code:00AB:04 + cheat + description:Have Clone Attack (glitch weapon) - P2 + code:00AB:18 + +cartridge sha256:0c190a8a7bfb57d7887e70183560db46fb5336abf569f6a38f5452fa32f1339f + title:Contra Force (USA) + cheat + description:Invincibility + code:SXKXZIAX+SXUZPIAX + cheat + description:Infinite lives (alt) + code:OUOXVKOO + cheat + description:Infinite lives - all characters + code:AANVIAPA + cheat + description:Keep weapons after death + code:OUEXNKOO + cheat + description:Start with 9 lives - all characters + code:PAUYTTLE + cheat + description:Start with 6 lives - all characters + code:TAUYTTLA + cheat + description:Start with 1 life - all characters + code:PAUYTTLA + +cartridge sha256:22ea833fd9466795bd2b05df96a47081ca45a26f545af1242f4c89b2d6688bdd + title:Cool World (USA) + cheat + description:Infinite lives + code:GXUVTKVK + cheat + description:Infinite Bombs + code:SXSTOTVG + cheat + description:Infinite Erasers + code:SXVVKTVG + cheat + description:Lots of Erasers + code:AZNZEYAE + cheat + description:Start with 3 Bombs + code:LEVLGZPA + cheat + description:Start with 6 Bombs + code:TEVLGZPA + cheat + description:Start with 9 Bombs + code:PEVLGZPE + cheat + description:Start with 2 lives + code:PEKGYAZA+PAKZKYZA + cheat + description:Start with 7 lives + code:TEKGYAZA+TAKZKYZA + cheat + description:Start with 10 lives + code:PEKGYAZE+PAKZKYZE + cheat + description:Start with 3 Erasers + code:LEKKGAPA+LAVXXYPA + cheat + description:Start with 6 Erasers + code:TEKKGAPA+TAVXXYPA + cheat + description:Start with 9 Erasers + code:PEKKGAPE+PAVXXYPE + cheat + description:Infinite energy + code:04E8:00 + +cartridge sha256:528d501320ed0276bbc542f03c7c05fb59f9eeb540cd0d39e7286b1542aa153a + title:Cowboy Kid (USA) + cheat + description:Infinite lives + code:OUNKEUOO + cheat + description:Infinite health + code:0698:08 + +cartridge sha256:23b16928a7615ec599536b17dd2026370e2e1a13835f61276ea383d6b4d3f8c0 + title:Crackout (USA) (Proto) + cheat + description:Infinite lives + code:SZNUXAVG + +cartridge sha256:fda4fd839497634df5e77b1842f88c05ffa0ac13a894c9ea288aedcd168489c3 + title:Crash 'n' the Boys - Street Challenge (USA) + cheat + description:Start with 99 Gold + code:OOVUAIIE + cheat + description:Start with 50 Gold + code:ASVUAIIA + +cartridge sha256:b504d0ebff8aa6439f1f9606526d8739f5007c1fdac31f9550caa7ca26edce16 + title:Crisis Force (Japan) + cheat + description:Infinite lives + code:SUNEITVI + cheat + description:Infinite Bombs + code:SLOEGVVS + cheat + description:Start on stage 2 + code:PAOGKLAA + cheat + description:Start on stage 3 + code:ZAOGKLAA + cheat + description:Start on stage 4 + code:LAOGKLAA + cheat + description:Start on stage 5 + code:GAOGKLAA + cheat + description:Start on stage 6 + code:IAOGKLAA + cheat + description:Start on stage 7 + code:TAOGKLAA + +cartridge sha256:7eca4ce264363ab8cc2c9aeb52f2e5be43a72a8223bac977492c7f8d78a49fb4 + title:Cross Fire (USA) (Proto) + cheat + description:Invincibility + code:ENVOALEI+ESVPLLEY + cheat + description:Infinite energy + code:OZNEPYES+SANELNSX + cheat + description:Infinite lives + code:SXUEYOVK + cheat + description:Protection from enemies + code:SXNNUXSE+SZEXLEVK + +cartridge sha256:5ad644d368f70b61700b74a1d04778888efcbbf98d5435d79f9fcefd23ac39c2 + title:Crystalis (USA) + cheat + description:Always fire charged shot + code:OZNOOKZK+PANOXKZG + cheat + description:Always fire bracelet charged shot + code:OZNOOKZK+LANOXKZG + cheat + description:Faster sword charge + code:AAOPETLA + cheat + description:Allow sword charge while moving + code:SZEPEVGK + cheat + description:First pupil gives you more gold + code:NYVSPZGV + cheat + description:Magic doesn't use up MP + code:SXNOVXSE + cheat + description:Immune to poison + code:AASVVNYA + cheat + description:Immune to paralysis + code:AEKTSNYA + cheat + description:Stronger poison + code:TEOTVYGA + cheat + description:Weaker poison + code:ZEOTVYGA + cheat + description:Walk through walls + code:AEKOUPTA + cheat + description:Don't get charged for boarding at Inn + code:SZUOIVSE+SZKPLVSE + cheat + description:Don't get charged for items in shops + code:SXVPUOSE+SXVOOOSE + cheat + description:Start with some gold + code:VVOGUOSE + +cartridge sha256:e239709320fca149b40a1f04625741dc2b6d3b9cc933d4062882ad762fa67ca7 + title:Cyberball (USA) + cheat + description:Infinite level time + code:SXUYAKVK + cheat + description:Start with level time at 1 minute + code:PENOYLLA + cheat + description:Start with level time at 2 minutes + code:ZENOYLLA + cheat + description:Start with level time at 5 minutes + code:IENOYLLA + cheat + description:Start with level time at 9 minutes + code:PENOYLLE + cheat + description:Goals worth 0 points + code:AAXEZAZA + cheat + description:Goals worth 1 points + code:PAXEZAZA + cheat + description:Goals worth 5 points + code:IAXEZAZA + cheat + description:Goals worth 9 points + code:PAXEZAZE + cheat + description:Goals worth mega points + code:LTXEZAZA + +cartridge sha256:ad1e14d08657d99c8b70f779931f62524b4beb529090b82b368925d8b642e40c + title:Cybernoid - The Fighting Machine (USA) + cheat + description:Infinite Bombs + code:SZNPVOVK + cheat + description:Infinite Genocides + code:SXEUSSVK + cheat + description:Infinite Shields + code:SXOPUSVK + cheat + description:Infinite Seekers + code:SZNOLNVK + cheat + description:20 Genocides on new life + code:GOOZZPZA + cheat + description:Keep rear laser after death + code:GZKZZOSE + cheat + description:Keep mace after death + code:GZKXAOSE+GZKZIOSE + cheat + description:Start with rear laser + code:NNOEPPAE + cheat + description:Start with infinite lives + code:SZVZGOVK + cheat + description:Start new life with 20 shields + code:GPUETZPA+GOOZYPPA + cheat + description:Start with 20 seekers and bouncers + code:GPKAZZIA+GOOXGPIA + cheat + description:Start with double Bombs + code:AZUALZGO+AXEXIPGO + cheat + description:Start with 1 life + code:NYEATXNY + cheat + description:Start with 5 lives + code:UYEATXNN + cheat + description:Start with 18 lives + code:AAEATXNN + cheat + description:Invincibility + code:06D4:00 + cheat + description:Infinite lives + code:06D5:FF + +cartridge sha256:9d832956a533292e740be553e0eb46d3a3d449578bcbaa9c7556a31d2b6a594d + title:D.J. Boy (Unl) + cheat + description:Infinite health + code:SZVAZVSO + cheat + description:Infinite time + code:SZOENISA + cheat + description:Infinite lives + code:SXENAYVG + +cartridge sha256:4cbf1c1d0be227127513065ccbc8ecf5e5ee61a7a58b6dea79ff01f0eb9f26af + title:Danny Sullivan's Indy Heat (USA) + cheat + description:Infinite turbos + code:SZELSOVS + cheat + description:Infinite fuel + code:SXVASVSO + cheat + description:Everything costs how much you have + code:SVKLTOSO + cheat + description:Don't take damage in the front + code:OUVZAXOO + cheat + description:Start with $255,000 + code:NYUOZLGV + +cartridge sha256:9b6d967f493a565e25b51aee044354f857c5cefc41f476d4f259e7368b1fdd70 + title:Darkman (USA) + cheat + description:Infinite health + code:SXKGUSSE + cheat + description:Infinite health (alt) + code:0496:37+04B5:37 + cheat + description:Infinite lives + code:0497:04 + +cartridge sha256:f97f05a4f8747d81dc8adaf07df70d1f87366632ae3e93103d387043ef5ec508 + title:Darkwing Duck (USA) + cheat + description:Invincibility + code:EYUEIPEI + cheat + description:Infinite health + code:AVVNSOOG + cheat + description:Infinite lives + code:GZOGSUVK + cheat + description:Infinite lives (alt) + code:SGOGSUVK + cheat + description:Infinite gas (if you avoid the "Go" missions) + code:AVUEUOSZ + cheat + description:More gas on pick-up + code:IYEAKPAY + cheat + description:Start with infinite health + code:SXNYUOSE + cheat + description:Start with 2 lives + code:PYSKXPLY + cheat + description:Start with 6 lives + code:IYSKXPLY + cheat + description:Start with 9 lives + code:AYSKXPLN + +cartridge sha256:227e789fef94eabcf24a5ec9a3944de58b183bbc7d96140269d1c908f162b853 + title:Dash Galaxy in the Alien Asylum (USA) + cheat + description:Invincibility + code:XVUGLNSX + cheat + description:No damage from shots and collisions + code:AAEPZIPA + cheat + description:Infinite Oxygen + code:SZOPISVK + cheat + description:Infinite Bombs in elevator shaft + code:VTNSEXSX + cheat + description:Infinite Bombs in rooms + code:VVVSXXSX + cheat + description:Infinite Detonators in shafts + code:VVOSSXSX + cheat + description:Infinite Detonators in rooms + code:VTESNUSX + cheat + description:Infinite Keys in shafts + code:VTEZIKSX + cheat + description:Infinite Keys in rooms + code:VVOXTOSX + cheat + description:Can't lose lives in rooms + code:SZVPTOVK + cheat + description:Can't lose lives in elevator shaft + code:SZUPLOVK + cheat + description:Oxygen used up more slowly in shaft + code:NYSXAOAN + cheat + description:Oxygen used up more quickly in rooms + code:AYXXSNNY + cheat + description:Start with 1 life + code:PENPIALA + cheat + description:Start with 6 lives + code:TENPIALA + cheat + description:Start with 9 lives + code:PENPIALE + cheat + description:Start with 99 lives + code:LVNPIALA + cheat + description:Start on level 5 + code:OZEPOISE+IAEPXSVI + cheat + description:Start on level 10 + code:OZEPOISE+ZAEPXSVS + cheat + description:Start on level 15 + code:OZEPOISE+YAEPXSVS + cheat + description:Start on level 20 + code:OZEPOISE+GPEPXSVI + +cartridge sha256:41f949cfedf7167985f779c0782ee17ee83d82e35111c5f22ee5037f54313a06 + title:Day Dreamin' Davey (USA) + cheat + description:Infinite health + code:SXSPZGSA + cheat + description:Hit anywhere + code:AANLZKZG + cheat + description:Infinite health (alt) + code:0067:FF + cheat + description:Infinite Small Spears + code:0411:99 + cheat + description:Infinite Long Spears + code:0412:99 + cheat + description:Infinite One Rock + code:0413:99 + cheat + description:Infinite Three Rock + code:0414:99 + cheat + description:Infinite Four Rock + code:0415:99 + cheat + description:Infinite Potions + code:041F:99 + cheat + description:Infinite Red Potions + code:0420:99 + cheat + description:Have Key + code:0420:01 + cheat + description:Have Ring + code:0422:01 + cheat + description:Have Pendant + code:0423:01 + cheat + description:Have Sword + code:040E:01 + cheat + description:Have Long Lance + code:040F:01 + cheat + description:Have Long Sword + code:0410:01 + cheat + description:Walk through walls + code:CE42:00+CED9:00+CF64:00+CFE0:00 + +cartridge sha256:9371fab4f58fa6d6e5211950fdaff2810cccff512fc301e88af9c5b1bf586257 + title:Days of Thunder (USA) + cheat + description:Faster acceleration + code:SXEYPUSU + cheat + description:Tires don't burst + code:AAVOEXNY + cheat + description:Better left-hand cornering + code:SNXOSKEY + cheat + description:Maximum acceleration + code:IEUNLLLA+SXEYPUSU + cheat + description:Start with more fuel + code:NYKNIUNO + cheat + description:Start with less fuel + code:YIKNIUNO + cheat + description:Infinite fuel + code:021F:FF + cheat + description:Always 1st place + code:0464:01 + cheat + description:Always excellent condition - front left tire + code:046C:00 + cheat + description:Always excellent condition - front right tire + code:046D:00 + cheat + description:Always excellent conditon - rear left tire + code:046E:00 + cheat + description:Always excellent condition - rear right tire + code:046F:00 + cheat + description:Always excellent condition - engine + code:0471:00 + cheat + description:Max speed + code:0473:15 + cheat + description:Lap 02 + code:0463:02 + cheat + description:Lap 03 + code:0463:03 + cheat + description:Lap 04 + code:0463:04 + cheat + description:Lap 05 + code:0463:05 + cheat + description:Lap 06 + code:0463:06 + cheat + description:Lap 07 + code:0463:07 + cheat + description:Lap 08 + code:0463:08 + cheat + description:Lap 09 + code:0463:09 + cheat + description:Lap 10 + code:0463:0A + +cartridge sha256:0115356b0791cc8ddcb7d3163d6ef7aa664f3ff4e68dba561ffffb79eefcbca9 + title:Deadly Towers (USA) + cheat + description:Infinite HP + code:GXSONPST + cheat + description:1 Ludder gives 10 on pick-up + code:ZEUPKYPE + cheat + description:5 Ludder gives 20 on pick-up + code:GOUPUYIA + cheat + description:Shopkeeper forgets to charge you + code:GXUGLVON + cheat + description:Start with 127 Ludder + code:YYXELPZU + cheat + description:Start with 75 Ludder + code:LGXELPZU + cheat + description:Always max Ludder + code:009B:FA + cheat + description:Max HP + code:01B3:FF + cheat + description:All belts burned (door on the right in the beginning of the game is now open) + code:01B4:07 + cheat + description:Slot 1 - Splendor (game's best sword) + code:0176:10 + cheat + description:Slot 2 - Hyper Helm + code:0177:04 + cheat + description:Slot 3 - Shield Of Kings + code:0178:08 + cheat + description:Slot 4 - Hyper Armor + code:0179:0C + cheat + description:Slot 5 - Hyper Boots + code:017A:14 + cheat + description:Slot 6 - Parallel Shot + code:017B:1A + +cartridge sha256:32aeef6bae170d2628d9c678f0b198a61e787a498a995eb374518635f0b55199 + title:Deathbots (USA) (Rev 1) (Unl) + cheat + description:Infinite energy + code:SLNZOXSO + cheat + description:Infinite lives + code:SXXZIEVK + cheat + description:Infinite shots + code:OLUZEVOO + +cartridge sha256:5dac8da44ac4e28bebf3d33c8e00e1fdffcc7baee3ff98bec5a10415d1226791 + title:Deathbots (USA) (Unl) + cheat + description:Infinite energy + code:SLNZOXSO + cheat + description:Infinite lives + code:SXXZIEVK + cheat + description:Infinite shots + code:OLUZEVOO + +cartridge sha256:bf58512dc3bc427d14a6d851445801967cd14f3d02ae236eabceeb7928a55462 + title:Defender II (USA) + cheat + description:Invincibility + code:SXVIOTSA + cheat + description:Infinite lives + code:GXTGEY + cheat + description:Infinite Smart Bombs + code:GXYSGI + cheat + description:Super speed + code:YAZVPG+YETVIL + cheat + description:Start with 1 life + code:PELGNY + cheat + description:Start with 6 lives + code:TELGNY + cheat + description:Start with 9 lives + code:PELGNN + +cartridge sha256:9e31d3d918a352c0c5a81c52efc364253f3fb75cc84151ee904ad078be62d8e1 + title:Defender of the Crown (USA) + cheat + description:Only 10 soldiers in your Garrison + code:ZAVVALGO + cheat + description:40 soldiers in your Garrison + code:AZVVALGO + cheat + description:Soldiers for free + code:AAEOUPPA + cheat + description:Triple the cost of soldiers + code:LAEOUPPA + cheat + description:Halve the cost of knights + code:GAEOKOAA + cheat + description:Double the cost of knights + code:APEOKOAA + cheat + description:Halve the cost of catapults + code:YAEOSOYA + cheat + description:Halve the cost of castles + code:ZAEOVPGO + +cartridge sha256:c408dd19ca49e55173ff2c491868f437d8100671f7b9646ee20e3204e0ba216f + title:Demon Sword - Release the Power (USA) + cheat + description:Invincibility + code:SZUEUZAX + cheat + description:Infinite health (life) + code:SZKGTTSA + cheat + description:Infinite powers and lives + code:AESVLTPA + cheat + description:Infinite lives + code:SXSIYASA + cheat + description:Phoenix always rescues you + code:VTVTAESX + cheat + description:Infinite Fire, Lightning, Power Beams on pick-up + code:SLNNANSO + cheat + description:Extra dart strength + code:VTNXAOSE + cheat + description:Start with 44 Red Spheres + code:XZNZGPSA+VEEZYOSE + cheat + description:Start with 44 Black Spheres + code:XZNZGPSA+VEEXZOSE + cheat + description:Start with 44 Fire Spheres + code:XZNZGPSA+VANXLOSE + cheat + description:Start with 44 Lightning Bolts + code:XZNZGPSA+VANXTOSE + cheat + description:Start with 44 Power Beams + code:XZNZGPSA+VEEZPOSE + cheat + description:Start with 1 life + code:AEVSUIZA + cheat + description:Start with 6 lives + code:IEVSUIZA + cheat + description:Start with 9 lives + code:AEVSUIZE + cheat + description:Start on level 2 + code:ATNXAOSA+PANZLPAA + cheat + description:Start on level 3 + code:ATNXAOSA+ZANZLPAA + cheat + description:Start on level 4 + code:ATNXAOSA+LANZLPAA + cheat + description:Start on level 5 + code:ATNXAOSA+GANZLPAA + cheat + description:Start on level 6 + code:ATNXAOSA+IANZLPAA + cheat + description:Infinite health (life) (alt) + code:007E:08 + cheat + description:Infinite Power + code:007C:0F + cheat + description:Infinite lives (alt) + code:007D:99 + cheat + description:Infinite Keys + code:0207:99 + cheat + description:Infinite Red Spheres + code:0208:99 + cheat + description:Infinite Black Spheres + code:0209:99 + cheat + description:Infinite Phoenix + code:020A:99 + +cartridge sha256:4b13643e53f2f7b43075233eebe65489d1d0a4ce3cf71a4f934178c3091930cf + title:Dengeki - Big Bang! (Japan) + cheat + description:Invincibility (blinking) + code:EOSOPALA+GXSPPAEY+OXSOAAES + +cartridge sha256:281ad7bdb4f94e2303d95c6078c20295e240b80370fdceda27950966b0e09198 + title:Desert Commander (USA) + cheat + description:Start with 99 Tank units + code:0084:63 + cheat + description:Start with 99 Tank #2 units + code:0085:63 + cheat + description:Start with 99 Truck units + code:0086:63 + cheat + description:Start with 99 Troop units + code:0087:63 + cheat + description:Start with 99 Grenade units + code:0088:63 + cheat + description:Start with 99 Stationary Artillery units + code:0089:63 + cheat + description:Start with 99 Transport Truck units + code:008A:63 + cheat + description:Start with 99 Heavy Airplane units + code:008B:63 + cheat + description:Start with 99 Light Airplane units + code:008C:63 + +cartridge sha256:44cd6b2aa05286c37e78bd04d15793018bb0656b24260e5c76fc5cfad39f699b + title:Destination Earthstar (USA) + cheat + description:Infinite lives + code:SXVSVIVG + cheat + description:Less energy + code:ISNEUUOP + cheat + description:More energy + code:NNNEUUOO + cheat + description:Don't lose special weapon in sub-game + code:XTNVSNXK + cheat + description:Start with 1 life + code:PAVTXGLA + cheat + description:Infinite energy (ten-thousand's digit) + code:05A8:99 + cheat + description:Infinite energy (hundred's digit) + code:05A9:75 + cheat + description:Infinite energy (ten's and one's digit) + code:05AA:76 + cheat + description:Infinite Ruby Laser + code:05AD:FF + cheat + description:Infinite Torpedos + code:05AF:FF + +cartridge sha256:6d082c801942ce6787b471428ab4c8a6acb3e21f3f38fa197f2aeb698d9a2d7e + title:Destiny of an Emperor (USA) + cheat + description:Buy 300 provisions for no money + code:AEKPZZGT + cheat + description:Buy 30,000 provisions for no money + code:AEKPIZYZ+AEKPTZAP + cheat + description:Dagger costs nothing + code:AENLULZL + cheat + description:Bandana costs nothing + code:AEVLKGZL + cheat + description:Flail costs nothing + code:AENUKLGT + cheat + description:Robe costs nothing + code:AEXLXGGT + cheat + description:Elixir A costs nothing + code:AEUUXLGP + cheat + description:Resurrect costs nothing + code:AEXUVLGT + cheat + description:Steed costs nothing + code:AEXLVUEG + cheat + description:Gullwing costs nothing + code:AEEUKUEG + cheat + description:Leather costs nothing + code:AEXUOKGZ+AEXUXGPA + +cartridge sha256:163479e2b1571538cf2f0f147bcbdebaab8ed8b0251f87dabd9bc4c80d786ea1 + title:Dick Tracy (USA) + cheat + description:Infinite health + code:GXVOINSV + cheat + description:Infinite hand gun bullets + code:SZXZEOVK + cheat + description:Infinite machine gun bullets + code:SXVXZEVK + cheat + description:Infinite super punches + code:SZKZIXVK + cheat + description:Infinite tear gas + code:SZEXIXVK + cheat + description:More super punches on pick-up + code:GOEPIOZA + cheat + description:Mega-jump + code:KYVZAANY + cheat + description:Take more damage + code:AOVOGNAU + cheat + description:Infinite health (alt) + code:0663:09 + cheat + description:Infinite hand gun bullets (alt) + code:0761:31 + +cartridge sha256:e060fd43ef58d6e022f1fcab853a388142fd68d4bbd00dedc095992152e27976 + title:Die Hard (USA) + cheat + description:Infinite health against Pistol ammo + code:SXEZTYSA + cheat + description:Infinite health against Submachine Gun ammo + code:SXOZIYSA + cheat + description:Infinite health against punches + code:SXXZLYSA + cheat + description:Infinite Pistol ammo + code:ATNALXVG + cheat + description:Infinite Submachine Gun ammo + code:ATNEIXVG + cheat + description:Infinite ammo on all guns + code:ATVEIZSZ + cheat + description:Infinite time + code:AVUNGPSZ + cheat + description:Lose foot health very slowly + code:SXOYYUSE + cheat + description:Time runs at 1/4 normal speed + code:ENUYPOGL + cheat + description:Time runs at 1/3 normal speed + code:KUUYPOGL + cheat + description:Time runs at 1/2 normal speed + code:ANUYPOGU + cheat + description:Time runs at 2x normal speed + code:TOUYPOGU + cheat + description:Time runs at 3x normal speed + code:GOUYPOGL + cheat + description:Time runs at 4x normal speed + code:YEUYPOGU + cheat + description:Start with no Pistol shots instead of 15 + code:AEXGPOYA + cheat + description:Start with 5 Pistol ammo + code:IEXGPOYA + cheat + description:Start with 10 Pistol ammo + code:ZEXGPOYE + cheat + description:Start with 20 Pistol ammo + code:GOXGPOYA + cheat + description:Start with 25 Pistol ammo + code:POXGPOYE + cheat + description:Start with 1 life point instead of 16 + code:PEOKIPAP + cheat + description:Start with 2 life points + code:ZEOKIPAP + cheat + description:Start with 4 life points + code:GEOKIPAP + cheat + description:Start with 8 life point + code:AEOKIPAO + cheat + description:Start with 12 life points + code:GEOKIPAO + cheat + description:Start with 20 life points + code:GOOKIPAP + cheat + description:Invincibility + code:00A5:05 + cheat + description:Infinite health (alt) + code:00AC:10 + cheat + description:Infinite feet health + code:0798:00 + cheat + description:Infinite time (alt) + code:00AF:60 + cheat + description:Immune to flashes + code:00A8:00 + cheat + description:0 crooks left + code:00AB:00 + cheat + description:Have all items + code:0779:FF + cheat + description:Infinite pistol ammo (alt) + code:077A:14 + cheat + description:Infinite Submachine Gun ammo (alt) + code:077B:64 + cheat + description:Infinite Submachine Gun cartridges + code:077C:07 + cheat + description:Infinite C4 + code:077D:05 + cheat + description:Infinite flashes + code:077E:07 + +cartridge sha256:721c464598519132fbb62f74c39a5b0ef67d1b74ebc571e77d33b5b2b4fae8c4 + title:Digger - The Legend of the Lost City (USA) + cheat + description:Infinite health + code:SXSYOPVG + cheat + description:Infinite lives + code:SXVAYTVG + cheat + description:Less rocks on pick-up + code:IAUGZUPA + cheat + description:Infinite rocks on pick-up + code:SZEYTVVK + cheat + description:Infinite rope on pick-up + code:SXEUIUVK + cheat + description:Infinite dynamite on pick-up + code:SXEXTEVK + cheat + description:Start with weapons + code:PAONOGAE + cheat + description:Infinite time (disable before exiting stage) + code:0187:09 + +cartridge sha256:7c8b6add50b20e4612e3043df0671e701cd2aa163e4af864913e3940feee27f2 + title:Dig Dug (Japan) + cheat + description:Infinite lives - both players + code:0060:03 + cheat + description:Start on stage 25 (disable after loading stage) + code:006E:18 + cheat + description:Start on stage 50 (disable after loading stage) + code:006E:31 + cheat + description:Start on stage 75 (disable after loading stage) + code:006E:4A + cheat + description:Start on stage 99 (disable after loading stage) + code:006E:63 + +cartridge sha256:1bf92138500e24a4e48da6d1f2eecbaeb3f36d28a425f06179fe9283381640e6 + title:Dig Dug II - Trouble in Paradise (USA) + cheat + description:Instant inflate and explode + code:GZETIZEI + cheat + description:Never lose lives from touching water + code:SZXLSVVK + cheat + description:Never lose lives from Fygar's flame + code:SXVKLVVK + cheat + description:Never lose lives from hitting enemies + code:SXNIPEVK + cheat + description:Turbo speed + code:OZNYPUPX+ZANYZLLA + cheat + description:Start with 1 life - both players + code:PEETOPLA + cheat + description:Start with 8 lives - both players + code:AEETOPLE + +cartridge sha256:5aaa8382ec79c170472840dfd8e9d93512bdf2be09ecd6b3709a9d27658888cd + title:Dirty Harry (USA) + cheat + description:Infinite health + code:GXXGXGST + cheat + description:Infinite lives + code:SXUKOKVK + cheat + description:Maximum health from Chili Dogs + code:AEVLIPZA + cheat + description:Only 10 Magnum Bullets allowed + code:ZESSTSPO+ZEVIZSPO + cheat + description:50 Magnum Bullets allowed + code:ZUSSTSPP+ZUVIZSPP + cheat + description:Start with 1 life + code:PANSGIIA + cheat + description:Start with 10 lives + code:ZANSGIIE + cheat + description:Infinite Time Bombs + code:06D3 63 + cheat + description:Infinite Hot Dogs + code:06D4 63 + cheat + description:Infinite Spear Gun + code:06D5 63 + cheat + description:Infinite Bazooka + code:06D6 63 + cheat + description:Infinite Rope + code:06D7 63 + cheat + description:Infinite Armor Vest + code:06D8 63 + cheat + description:Infinite Mask + code:06D9 63 + cheat + description:Infinite Flashlight + code:06DA 63 + cheat + description:Infinite Prybars + code:06DB 63 + +cartridge sha256:65295da1f14578b659b6613be80d0516c2a4932dc6bc33bad2cc71a3154672e7 + title:Doki! Doki! Yuuenchi (Japan) + cheat + description:Invincibility + code:APEPPPAL + cheat + description:Infinite hits + code:SXVXENVK + cheat + description:Infinite lives + code:SXSSKNVK + +cartridge sha256:aa408f5a6b97c0d738e7e8b489a5617ad4a9ecdee2b05c4ee504210ce31b2825 + title:Donkey Kong (World) (Rev A) + cheat + description:Invincible against barrels + code:SXXVKGSA + cheat + description:Invincible against fireballs + code:SXUTXISA + cheat + description:Infinite lives + code:SXNGOZVG + cheat + description:Hammer lasts 3.4 times longer + code:NYUITVLK + cheat + description:Start with 1 life + code:PENKNPLA + cheat + description:Start with 9 lives + code:PENKNPLE + +cartridge sha256:b15b298dc37692d0bed2cbf922727ea48ed38bbd6cf3acdd28be6d2b9be344d3 + title:Donkey Kong 3 (World) + cheat + description:Invincibility + code:AVVGELEY + cheat + description:Reduce the time for pros + code:ZEKKGYEE + cheat + description:Normal spray more powerful + code:ZAOSZAPA + cheat + description:Normal spray longer + code:ZLOSLAAA + cheat + description:Spray cuts through baddies + code:AASSYPPA + cheat + description:Normal bees explode + code:AAKVZALL + cheat + description:Speeding Stanley + code:TEXKVGLA + cheat + description:Start with infinite lives + code:SZNKOPVI + cheat + description:Start with 1 life + code:PEEGITLA + cheat + description:Start with 9 lives + code:PEEGITLE + +cartridge sha256:950ebe68e7f74219b9e5e104200b03165d59c24264f02e32c12be967fd311ac2 + title:Donkey Kong Jr. (World) (Rev A) + cheat + description:Cannot die from falling from a high platform + code:PAUIEZIA + +cartridge sha256:234c2f62cbc3c72eb7519425a1893229e19a3fd1b1630fb75f3e951960a300e5 + title:Donkey Kong Classics (USA, Europe) + cheat + description:Donkey Kong - Infinite lives + code:SXYAOP + cheat + description:Donkey Kong - Start with 1 life + code:PETANA + cheat + description:Donkey Kong - Start with 6 lives + code:TETANA + cheat + description:Donkey Kong - Start with 9 lives + code:PETANE + cheat + description:Donkey Kong - Controllable jump + code:AEVAVSIA + cheat + description:Donkey Kong - Keep hammer longer + code:EAKOLSLG + cheat + description:Donkey Kong Jr - Infinite lives + code:SZZGTP + cheat + description:Donkey Kong Jr - Start with 1 life + code:PATLST + cheat + description:Donkey Kong Jr - Start with 6 lives + code:TATLST + cheat + description:Donkey Kong Jr - Start with 9 lives + code:PATLSV + cheat + description:Donkey Kong Jr - Controllable jump + code:AEKGAUIA + cheat + description:Donkey Kong Jr - Faster single vine climbing + code:EAVGVIAG + cheat + description:Donkey Kong Jr - Can fall onto platforms + code:PAXIPAIA + cheat + description:Donkey Kong Jr - Speed up + code:EXSKSGEY+EXUKNGEY + +cartridge sha256:56cb5897c539b6874e311a314767df85186184690f10d9982b02cb90ff606537 + title:Double Dare (USA) + cheat + description:Infinite time to answer questions + code:SXXANUVK + +cartridge sha256:8f2f9ba926280edd3652745e1d04a30ecce64089fbf3f022a35b4039a2dd7b66 + title:Double Dragon (USA) + cheat + description:Infinite lives + code:EEUTLZZE + cheat + description:Infinite time + code:AAUNYLPA + cheat + description:Gain hearts quickly + code:VKKYXLVT + cheat + description:Gain a heart every time you hit an enemy + code:EKINNL + cheat + description:More health - P1 + code:XTKYOEZK + cheat + description:More health - P2 or computer + code:XTKNXEZK + cheat + description:No enemies + code:IIIOOO + cheat + description:Enemies will not fight back + code:IIIEOO + cheat + description:Slow motion + code:KOTKOK + cheat + description:Timer will count down faster + code:AZUYZLAL + cheat + description:Timer will count down super-fast + code:APUYZLAL + cheat + description:Disable level 4 wall trap + code:NYZSIU + cheat + description:Start with 1 life + code:AEUTLZZA + cheat + description:Start with 6 lives + code:IEUTLZZA + cheat + description:Start with 9 lives + code:AEUTLZZE + cheat + description:Infinite health + code:03B4:64 + cheat + description:Start with all hearts + code:0040:07 + cheat + description:Start on stage 2 (disable after stage begins) + code:003D:01 + cheat + description:Start on stage 3 (disable after stage begins) + code:003D:02 + cheat + description:Start on stage 4 (disable after stage begins) + code:003D:03 + +cartridge sha256:c564704993cf79c94db5c2954792e99e86100586d0ef1d4bf1aefc6d008d4c0f + title:Double Dragon II - The Revenge (USA) (Rev A) + cheat + description:No enemies + code:ZYZPPA + cheat + description:Never lose lives from falling + code:SZXAYKVS + cheat + description:Never lose lives from low energy + code:SXOANXVS + cheat + description:Never lose lives from water + code:SZVESUVS + cheat + description:Uppercut after only two punches + code:PAVUELZA + cheat + description:Slow down gameplay + code:NNEVOIAE + cheat + description:Start with 259 lives - P1 + code:NYSVETGE + cheat + description:Start with 8 lives - P1 + code:AASVETGE + cheat + description:Start with 8 lives - P2 + code:AAVVSTGE + cheat + description:Start with 1 life - P1 + code:PASVETGA + cheat + description:Start with 1 life - P2 + code:PAVVSTGA + cheat + description:Start on mission 2 + code:PAUTXTAA + cheat + description:Start on mission 3 + code:ZAUTXTAA + cheat + description:Start on mission 4 + code:LAUTXTAA + cheat + description:Start on mission 5 + code:IAUTXTAA + cheat + description:Start on mission 6 + code:TAUTXTAA + cheat + description:Start on mission 7 + code:PAUTXTAE + cheat + description:Start on mission 8 + code:GAUTXTAE + cheat + description:Start at final boss + code:TAUTXTAE + cheat + description:Start at final boss (alt) + code:TALTXV + cheat + description:Invincibility + code:03CC:F0 + cheat + description:Enemies die after one knockdown (disable at final boss) + code:0420:00+0421:00 + +cartridge sha256:f329de1e2653499221dc4d14d0e8b1040fee87bda4daccf6098b316a1a024fe2 + title:Double Dragon II - The Revenge (USA) + cheat + description:No enemies + code:ZYZPPA + cheat + description:Never lose lives from falling + code:SZXAYKVS + cheat + description:Never lose lives from low energy + code:SXOANXVS + cheat + description:Never lose lives from water + code:SZVESUVS + cheat + description:Uppercut after only two punches + code:PAVUELZA + cheat + description:Slow down gameplay + code:NNEVOIAE + cheat + description:Start with 259 lives - P1 + code:NYSVETGE + cheat + description:Start with 8 lives - P1 + code:AASVETGE + cheat + description:Start with 8 lives - P2 + code:AAVVSTGE + cheat + description:Start with 1 life - P1 + code:PASVETGA + cheat + description:Start with 1 life - P2 + code:PAVVSTGA + cheat + description:Start on mission 2 + code:PAUTXTAA + cheat + description:Start on mission 3 + code:ZAUTXTAA + cheat + description:Start on mission 4 + code:LAUTXTAA + cheat + description:Start on mission 5 + code:IAUTXTAA + cheat + description:Start on mission 6 + code:TAUTXTAA + cheat + description:Start on mission 7 + code:PAUTXTAE + cheat + description:Start on mission 8 + code:GAUTXTAE + cheat + description:Start at final boss + code:TAUTXTAE + cheat + description:Start at final boss (alt) + code:TALTXV + cheat + description:Invincibility + code:03CC:F0 + cheat + description:Enemies die after one knockdown (disable at final boss) + code:0420:00+0421:00 + +cartridge sha256:9f5891d333ea410c9a20f952ed21ec8b35c1b4f2a6fc2408fb2510921b64660f + title:Double Dragon III - The Sacred Stones (USA) + cheat + description:Infinite health - Bill, Jimmy and Chin + code:SZUUPAAX + cheat + description:Infinite special weapons - everyone + code:AAELIGPA+GZXUPUVS + cheat + description:More powerful punch, weapon and high kick + code:OZVLGASX + cheat + description:More health - Billy and Jimmy + code:GVEPXGGI + cheat + description:More health - Ranzou + code:GVEOXKZG + cheat + description:Less health - Billy and Jimmy + code:ZXEPXGGS + cheat + description:Less health - Ranzou + code:IXEOXKZG + cheat + description:Less health - Chin + code:ZUEONGGT + cheat + description:Start with Chin enabled + code:AEULUKYA + cheat + description:Start with Ranzou enabled + code:AEKLVKAA + cheat + description:Start with Jimmy enabled + code:AEKNPPIA + cheat + description:Start with 255 health - Billy and Jimmy + code:NNEPXGGS + cheat + description:Start with 255 health - Chin + code:NNEONGGV + cheat + description:Start with 255 health - Ranzou + code:NNEOXKZK + cheat + description:Start with 99 weapon use - Billy, Jimmy and Chin + code:LVOPKGIA + cheat + description:Infinite health - P1 + code:045D:40 + cheat + description:Infinite health - P2 + code:045E:40 + +cartridge sha256:eb0e5f318e84e931a9bd663764c43fefa1a78565fa1328c1544b41bc8155ccb1 + title:Double Dribble (USA) (Rev A) + cheat + description:CPU scores add to your score + code:KNEKPKEY + cheat + description:CPU never scores + code:KNEKPKEN + cheat + description:50 points - team 1 + code:07F4:50 + cheat + description:50 points - team 2 + code:07F8:50 + +cartridge sha256:f5517606d81d4e993d7fb86f11cae24c7b5029fd7184c7247771d6d7791e54ab + title:Double Dribble (USA) + cheat + description:CPU scores add to your score + code:KNEKPKEY + cheat + description:CPU never scores + code:KNEKPKEN + cheat + description:50 points - team 1 + code:07F4:50 + cheat + description:50 points - team 2 + code:07F8:50 + +cartridge sha256:ddc08430b83061814fec929872aa6df3abc1a624888a8e3eb3fa96abb8d32e36 + title:Double Moon Densetsu (Japan) + cheat + description:Play as girl + code:ESSUGTEY + +cartridge sha256:aa3b652591a7310e6e2cc025deabd9accf49506bd2313265fee67f2c5e83036a + title:Drac's Night Out (USA) (Proto) + cheat + description:Infinite Blood + code:SZSGAVSE + cheat + description:Infinite time + code:SVNKTSVV + +cartridge sha256:af505b8530b3303ebe0bf727730733cdbcd83ce1a19781d9487cd7cb202933c1 + title:Dragon Fighter (USA) + cheat + description:Invincibility + code:EYEVAIEI + cheat + description:Invincibility (alt) + code:004D:4F + cheat + description:Invincible to spikes + code:AESSILPA + cheat + description:Infinite health + code:SZSVGISA + cheat + description:Max Dragon energy + code:KAUIEGSZ + cheat + description:Always shoot special + code:YYXSYZAE + cheat + description:Infinite health (alt) + code:0050:08 + cheat + description:Max Dragon energy (alt) + code:0053:18 + cheat + description:Have green shots + code:004F:00 + cheat + description:Have red shots + code:004F:01 + cheat + description:Have blue shots + code:004F:02 + cheat + description:Hard mode + code:007B:01 + +cartridge sha256:038f2241fd6e58600ce234623be752cca47875ef7295fe92c30c328c81ffe7ec + title:Dragon Power (USA) + cheat + description:Infinite health (POW) + code:SZVOSZVG + cheat + description:Start with 128 health (POW) + code:EAXAILGT + cheat + description:Start with 24 Wind Waves (turtle shells) (hold B then press A) + code:KAOETLSA + cheat + description:Infinite health (POW) (alt) + code:002E:63 + cheat + description:Infinite Wind Waves (turtle shells) (hold B then press A) + code:012F:09 + cheat + description:Infinite Red Power Pole time (spin attack) + code:0036:0F + +cartridge sha256:901b7a9b3e8c0256bd091f845f48b0e7bd903f7456ce3dcea386cc1871fe70c1 + title:Dragon Spirit - The New Legend (USA) + cheat + description:Invincibility and three heads after one hit (blinking) + code:EXAXEU + cheat + description:Infinite health + code:OZVZOZVG + cheat + description:Hit anywhere + code:OXNLEIES+OXXLOIES + cheat + description:Always gold dragon + code:VEOIKAKA + cheat + description:Always blue dragon + code:KXOIKAKA + cheat + description:Invincibility + code:0588:00 + +cartridge sha256:5564e54943deddc6d290b256638c774aa379a0d33dcea3b0a4f0c4b9fc2034e3 + title:Dragon's Lair (USA) + cheat + description:Infinite E (health) + code:AEXSGEKY + cheat + description:Infinite Candle energy + code:SXKYUOVK+SXVYXOVK + cheat + description:Infinite lives + code:AAXITVNY + cheat + description:Less energy gained on pick-up + code:IAVNPYAP + cheat + description:More energy gained on pick-up + code:YZVNPYAP + cheat + description:Start with Axe + code:PEUIGIAA + cheat + description:Start with Fireball + code:ZEUIGIAA + cheat + description:Start with 1 extra life + code:NNXSGSUY + cheat + description:Start with 6 extra lives + code:KNXSGSUN + cheat + description:Start with 9 extra lives + code:NNXSGSUN + cheat + description:Start on level 2 + code:PANSZIAA + cheat + description:Start on level 3 + code:ZANSZIAA + cheat + description:Start on level 4 + code:LANSZIAA + cheat + description:Infinite E (health) (alt) + code:0330:1F + cheat + description:Infinite Gold (hundred's digit) + code:05EA:FF + cheat + description:Infinite Gold (ten's digit) + code:05EB:FF + cheat + description:Infinite Gold (one's digit) + code:05EC:FF + +cartridge sha256:abc5bcb459316a7d245065149ea72b5a8317f62fa6ed578569e15b670d3c0022 + title:Dragon Warrior (USA) + cheat + description:Infinite Magic Power + code:SXOIVLSA + cheat + description:Take no damage in swamp + code:AEVGUIZA + cheat + description:Start with 256 gold coins + code:VVOYYTSA + cheat + description:All spells use only one magic point + code:VKOIVLSA + cheat + description:Barriers cause half usual damage + code:YAKKEVYA + +cartridge sha256:c15ab051ff066f018cf4b0159780c58026114bb47a6376ef81c1571a39a8fe9b + title:Dragon Warrior II (USA) + cheat + description:Prince of Midenhall starts with 50 HP + code:ZUKLUSGP + cheat + description:Prince of Midenhall starts with 99 HP + code:LVKLUSGP + cheat + description:Prince of Midenhall starts with 40 strength points + code:AXKLOIIE + cheat + description:Prince of Midenhall starts with 80 strength points + code:ASKLOIIA + cheat + description:Prince of Midenhall starts with 40 agility points + code:AXKLXIGE + cheat + description:Prince of Midenhall starts with 80 agility points + code:ASKLXIGA + cheat + description:Prince of Cannock starts with 50 HP + code:ZUKLNSYP + cheat + description:Prince of Cannock starts with 99 HP + code:LVKLNSYP + cheat + description:Prince of Cannock starts with 40 strength points + code:AXKLSIGE + cheat + description:Prince of Cannock starts with 60 strength points + code:GUKLSIGE + cheat + description:Prince of Cannock starts with 30 agility points + code:TOKLVIGE + cheat + description:Prince of Cannock starts with 60 agility points + code:GUKLVIGE + cheat + description:Prince of Cannock starts with 40 magic points + code:AXKUEITE + cheat + description:Prince of Cannock starts with 60 magic points + code:GUKUEITE + cheat + description:Princess of Moonbrooke starts with 50 HP + code:ZUKUUIAZ + cheat + description:Princess of Moonbrooke starts with 99 HP + code:LVKUUIAZ + cheat + description:Princess of Moonbrooke starts with 25 strength points + code:POKUOIZE + cheat + description:Princess of Moonbrooke starts with 50 strength points + code:ZUKUOIZA + cheat + description:Princess of Moonbrooke starts with 40 agility points + code:AXKUXITO + cheat + description:Princess of Moonbrooke starts with 40 magic points + code:AXKUKSGO + +cartridge sha256:f91a8bfc25bd267f5ae77bafa7fc650f77f8e50067869e99682b32d5b410644e + title:Dragon Warrior III (USA) + cheat + description:King gives 255 gold + code:NYUOYPZU + cheat + description:King gives mega-gold + code:PASPZPAA + cheat + description:Player starts with increased strength and/or attack power + code:YTVUGZYE + cheat + description:Player starts with greatly increased strength and/or attack power + code:VYVUGZYE + cheat + description:Player starts with increased agility and/or defense + code:LTNLPZIA + cheat + description:Player starts with greatly increased agility and/or defense + code:NYNLPZIE + cheat + description:Player starts with increased vitality and/or HP + code:LTNLTZYA + cheat + description:Player starts with greatly increased vitality and/or HP + code:NYNLTZYE + cheat + description:Player starts with increased magic, maximum magic points and/or intelligence + code:LTNULZTA + cheat + description:Player starts with greatly increased magic, maximum magic points and/or intelligence + code:NYNULZTE + cheat + description:Player starts with increased luck + code:ZVELAZGA + cheat + description:Player starts with greatly increased luck + code:VNELAZGE + cheat + description:Wizard starts with increased strength and/or attack power + code:LTVUIZPA + cheat + description:Wizard starts with greatly increased strength and/or attack power + code:VYVUIZPE + cheat + description:Wizard starts with increased agility and/or defense + code:ZTNLZZGA + cheat + description:Wizard starts with greatly increased agility and/or defense + code:NYNLZZGE + cheat + description:Wizard starts with increased vitality and/or maximum HP + code:ZTNLYZZA + cheat + description:Wizard starts with greatly increased vitality and/or maximum HP + code:OPNLYZZE + cheat + description:Wizard starts with increased magic, intelligence and/or maximum magic + code:LTNUGXPA + cheat + description:Wizard starts with increased luck + code:LVELPZZA + cheat + description:Wizard starts with greatly increased luck + code:VNELPZZE + cheat + description:Pilgrim starts with increased strength and/or attack power + code:ZTVUTZLA + cheat + description:Pilgrim starts with greatly increased strength and/or attack power + code:VYVUTZLE + cheat + description:Pilgrim starts with increased agility and/or defense + code:ZTNLLZGA + cheat + description:Pilgrim starts with increased vitality and/or maximum HP + code:LTNUAZLA + cheat + description:Pilgrim starts with greatly increased vitality and/or maximum HP + code:VYNUAZLE + cheat + description:Pilgrim starts with increased magic and/or intelligence + code:LTNUIXAA + cheat + description:Pilgrim starts with greatly increased magic and/or intelligence + code:VYNUIXAE + cheat + description:Pilgrim starts with increased luck + code:ZVELZZLA + cheat + description:Pilgrim starts with greatly increased luck + code:VNELZZLE + cheat + description:Soldier starts with increased strength and/or attack power + code:LTNLAXPA + cheat + description:Soldier starts with greatly increased strength and/or attack power + code:VYNLAXPE + cheat + description:Soldier starts with increased agility and/or defense + code:ZTNLIZZA + cheat + description:Soldier starts with increased vitality and/or maximum HP + code:LTNUZZYA + cheat + description:Start with 6 battle-axes + code:IAOZENNY + cheat + description:Start with 6 broadswords + code:TAOZENNY + cheat + description:Start with 6 wizard's wands + code:YAOZENNY + cheat + description:Start with 6 demon's axes + code:YAOZENNN + cheat + description:Start with 6 multi-edge swords + code:GPOZENNY + cheat + description:Start with 6 staffs of force + code:IPOZENNY + cheat + description:Start with 6 swords of illusion + code:TPOZENNY + cheat + description:Start with 6 falcon swords + code:APOZENNN + cheat + description:Start with 6 armor of radiance + code:AZOZENNN + +cartridge sha256:e49cb745370065a40aff078ae52b5de1c0db137fedcbe93b78ab18d76479deed + title:Dragon Warrior IV (USA) + cheat + description:No damage and lose no MP - all members (don't combine with the "start with items" codes) + code:ATVATGSL + cheat + description:Start Chapter 1 with 25 gold + code:POSOAPZU + cheat + description:Start Chapter 1 with 100 gold + code:GVSOAPZL + cheat + description:Start Chapter 1 with 255 gold + code:NNSOAPZU + cheat + description:Start Chapter 1 with lots 'o gold + code:AIXOZAYS + cheat + description:Start Chapter 1 with 15 HP + code:YEEXYXLO + cheat + description:Start Chapter 1 with 100 HP + code:GVEXYXLP + cheat + description:Start Chapter 1 with 255 HP + code:NNEXYXLO + cheat + description:Start Chapter 1 with final key + code:LNKPLONY + cheat + description:Start Chapter 1 with metal babble sword + code:TEKPLONN + cheat + description:Start Chapter 1 with multi-edge sword + code:LOKPLONY + cheat + description:Start Chapter 1 with thorn whip + code:PEKPLONN + cheat + description:Start Chapter 1 with shield of strength + code:AKKPLONY + cheat + description:Start Chapter 1 with dragon shield + code:LKKPLONY + cheat + description:Start Chapter 1 with final key and chain sickle + code:LNKPLONY+GEKPGONY + cheat + description:Start Chapter 1 with metal babble sword and boomerang + code:TEKPLONN+LEKPGONN + cheat + description:Start Chapter 1 with multi-edge sword and wizard's ring + code:LOKPLONY+PSKPGONN + cheat + description:Start Chapter 1 with thorn whip and demon hammer + code:PEKPLONN+ZOKPGONY + cheat + description:Start Chapter 1 with shield of strength and meteorite armband + code:AKKPLONY+ASKPGONY + cheat + description:Start Chapter 1 with dragon shield and iron fan + code:LKKPLONY+IEKPGONN + cheat + description:Start Chapter 2 with 50 gold + code:ZUSOPPGT + cheat + description:Start Chapter 2 with 255 gold + code:NNSOPPGV + cheat + description:Start Chapter 2 with lots of gold + code:AIXOZAYS + cheat + description:Start Alena with 100 HP + code:GVOZAZAP + cheat + description:Start Alena with 255 HP + code:NNOZAZAO + cheat + description:Start Alena with final key + code:LNKOZONY + cheat + description:Start Alena with fire claw + code:ZOKOZONN + cheat + description:Start Alena with multi-edge sword + code:LOKOZONY + cheat + description:Start Alena with thorn whip + code:PEKOZONN + cheat + description:Start Alena with boomerang + code:LEKOLONN + cheat + description:Start Alena with final key and fire claw + code:LNKOZONY+ZOKOLONN + cheat + description:Start Alena with multi-edge sword and wizard's ring + code:LOKOZONY+PSKOLONN + cheat + description:Start Alena with thorn whip and demon hammer + code:PEKOZONN+ZOKOLONY + cheat + description:Start Alena with shield of strength and meteorite arm band + code:AKKOZONY+ASKOLONY + cheat + description:Start Alena with dragon shield and iron fan + code:LKKOZONY+IEKOLONN + cheat + description:Start Brey with final key + code:LNUPLONY + cheat + description:Start Brey with magma staff + code:TOUPLONN + cheat + description:Start Brey with multi-edge sword + code:LOUPLONY + cheat + description:Start Brey with thorn whip + code:PEUPLONN + cheat + description:Start Brey with shield of strength + code:AKUPLONY + cheat + description:Start Brey with dragon shield + code:LKUPLONY + cheat + description:Start Brey with boomerang + code:LEUPGONN + cheat + description:Start Brey with final key and magma staff + code:LNUPLONY+TOUPGONN + cheat + description:Start Brey with multi-edge sword and wizard's ring + code:LOUPLONY+PSUPGONN + cheat + description:Start Brey with thorn whip and demon hammer + code:PEUPLONN+ZOUPGONY + cheat + description:Start Brey with shield of strength and meteorite arm band + code:AKUPLONY+ASUPGONY + cheat + description:Start Brey with dragon shield and iron fan + code:LKUPLONY+IEUPGONN + cheat + description:Start Cristo with final key + code:LNOOLONY + cheat + description:Start Cristo with metal babble sword + code:TEOOLONN + cheat + description:Start Cristo with multi-edge sword + code:LOOOLONY + cheat + description:Start Cristo with thorn whip + code:PEOOLONN + cheat + description:Start Cristo with shield of strength + code:AKOOLONY + cheat + description:Start Cristo with dragon shield + code:LKOOLONY + cheat + description:Start Cristo with final key and chain sickle + code:LNOOLONY+GEOOGONY + cheat + description:Start Cristo with metal babble sword and boomerang + code:TEOOLONN+LEOOGONN + cheat + description:Start Cristo with multi-edge sword and wizard's ring + code:LOOOLONY+PSOOGONN + cheat + description:Start Cristo with thorn whip and demon hammer + code:PEOOLONN+ZOOOGONY + cheat + description:Start Cristo with shield of strength and meteorite arm band + code:AKOOLONY+ASOOGONY + cheat + description:Start Cristo with dragon shield and iron fan + code:LKOOLONY+IEOOGONN + cheat + description:Start Chapter 3 with 16 HP + code:AOEXTZGP + cheat + description:Start Chapter 3 with 100 HP + code:GVEXTZGP + cheat + description:Start Chapter 3 with 255 HP + code:NNEXTZGO + cheat + description:Start Chapter 3 with 100 gold + code:GVSOZPAA + cheat + description:Start Chapter 3 with 255 gold + code:NNSOZPAE + cheat + description:Start Chapter 3 with final key + code:UNUOLONY + cheat + description:Start Chapter 3 with metal babble sword + code:LEUOLONN + cheat + description:Start Chapter 3 with multi-edge sword + code:TOUOLONY + cheat + description:Start Chapter 3 with thorn whip + code:LEUOLONN + cheat + description:Start Chapter 3 with shield of strength + code:PKUOLONY + cheat + description:Start Chapter 3 with dragon shield + code:AKUOLONY + cheat + description:Start Chapter 3 with final key and chain sickle + code:LNUOLONY+GEUOGONY + cheat + description:Start Chapter 3 with metal babble sword and boomerang + code:TEUOLONN+LEUOGONN + cheat + description:Start Chapter 3 with multi-edge sword and wizard's ring + code:LOUOLONY+PSUOGONN + cheat + description:Start Chapter 3 with thorn whip and demon hammer + code:PEUOLONN+ZOUOGONY + cheat + description:Start Chapter 3 with shield of strength and meteorite arm band + code:AKUOLONY+ASUOGONY + cheat + description:Start Chapter 3 with dragon shield and iron fan + code:LKUOLONY+IEUOGONN + cheat + description:Start Nara with 100 HP + code:GVEXLZZP + cheat + description:Start Nara with 255 HP + code:NNEXLZZO + cheat + description:Start Nara with final key + code:LNXPLONY + cheat + description:Start Nara with metal babble sword + code:TEXPLONN + cheat + description:Start Nara with multi-edge sword + code:LOXPLONY + cheat + description:Start Nara with thorn whip + code:PEXPLONN + cheat + description:Start Nara with shield of strength + code:AKXPLONY + cheat + description:Start Nara with dragon shield + code:LKXPLONY + cheat + description:Start Nara with final key and chain sickle + code:LNXPLONY+GEXPGONY + cheat + description:Start Nara with metal babble sword and boomerang + code:TEXPLONN+LEXPGONN + cheat + description:Start Nara with multi-edge sword and wizard's ring + code:LOXPLONY+PSXPGONN + cheat + description:Start Nara with thorn whip and demon hammer + code:PEXPLONN+ZOXPGONY + cheat + description:Start Nara with shield of strength and meteorite arm band + code:AKXPLONY+ASXPGONY + cheat + description:Start Nara with dragon shield and iron fan + code:LKXPLONY+IEXPGONN + cheat + description:Start Mara with 100 HP + code:GVEXGZAP + cheat + description:Start Mara with 255 HP + code:NNEXGZAO + cheat + description:Start Mara with final key + code:LNXOPONY + cheat + description:Start Mara with magma staff + code:TOXOPONN + cheat + description:Start Mara with multi-edge sword + code:LOXOPONY + cheat + description:Start Mara with thorn whip + code:PEXOPONN + cheat + description:Start Mara with shield of strength + code:AKXOPONY + cheat + description:Start Mara with dragon shield + code:LKXOPONY + cheat + description:Start Mara with final key and chain sickle + code:LNXOPONY+GEXOZONY + cheat + description:Start Mara with metal babble sword and boomerang + code:TEXOPONN+LEXOZONN + cheat + description:Start Mara with multi-edge sword and wizard's ring + code:LOXOPONY+PSXOZONN + cheat + description:Start Mara with thorn whip and demon hammer + code:PEXOPONN+ZOXOZONY + cheat + description:Start Mara with shield of strength and meteorite arm band + code:AKXOPONY+ASXOZONY + cheat + description:Start Mara with dragon shield and iron fan + code:LKXOPONY+IEXOZONN + cheat + description:Start Chapter 5 with final key + code:LNOPIONY + cheat + description:Start Chapter 5 with zenithian sword + code:PXOPIONY + cheat + description:Start Chapter 5 with zenithian shield + code:GKOPIONY + cheat + description:Start Chapter 5 with zenithian armor + code:YUOPIONY + cheat + description:Start Chapter 5 with zenithian helmet + code:LKOPIONN + +cartridge sha256:a0b2ec9b44033fc4d2356259ad99a4f2dcdf5396da53efdfcb17a54c0e7fcdbe + title:Dr. Chaos (USA) + cheat + description:Infinite life + code:GXKIKIST + cheat + description:Take minimal damage + code:OVKIKISV+PEKISIGY + cheat + description:Infinite Gun ammo on pick-up + code:GZEYEEVK + cheat + description:More invincibility time + code:AKSSKIGP + cheat + description:Less invincibility time + code:GESSKIGP + cheat + description:Take more damage and Shield Suit has no effect + code:TVOSSITG+AEOSKIYA + cheat + description:Mega-jump + code:AEEGUZLE + cheat + description:Start with Shield Suit + code:PASKSPAA+ZISKNPLG + cheat + description:Start with 99 life + code:LTKKVPZL + cheat + description:Start with less health + code:PPKKVPZU + cheat + description:Invincibility (blinking) + code:0073:03 + cheat + description:Infinite life (alt) + code:0744:FF + cheat + description:Infinite Gun ammo + code:0746:63 + cheat + description:Infinite Machine Gun ammo + code:0747:63 + cheat + description:Infinite Grenades + code:0748:63 + +cartridge sha256:5860e217030f9da957d487b3ca59000d5f4d79bf23486bad08205c5aa4d992ea + title:Dr. Jekyll and Mr. Hyde (USA) + cheat + description:Infinite life + code:GZXVTKVK+GZXTTSVK + cheat + description:Multi-jump + code:NKNGVYUK+PXNKENOK+PENKOYGA+ENNKXYEI+PENKSYAA+OUNKNYUK + cheat + description:Keep coins from previous games + code:GXNLKVSE + cheat + description:Instant game restart + code:NXNSZEOO + cheat + description:Start with 16 coins + code:KENLKVSE + +cartridge sha256:01d303a8c0ed6f374586d3a2562065b77f627e8dbf071bd919877e3b48dbdb57 + title:Dr. Mario (Japan, USA) + cheat + description:Vitamin capsules don't fall (press down) + code:GZNEVIVT + cheat + description:5 in a row needed to complete a vertical line instead of 4 + code:GEXPYGLA + cheat + description:6 in a row needed to complete a vertical line instead of 4 + code:IEXPYGLA + cheat + description:7 in a row needed to complete a vertical line instead of 4 + code:TEXPYGLA + cheat + description:5 in a row needed to complete a horizontal line instead of 4 + code:GAKPPZLA + cheat + description:6 in a row needed to complete a horizontal line instead of 4 + code:IAKPPZLA + cheat + description:7 in a row needed to complete a horizontal line instead of 4 + code:TAKPPZLA + cheat + description:More pieces sent across to other player when two or more rows or columns are eliminated at once in a 2P game + code:AUVONUAO + cheat + description:No pieces sent across to other player when two or more rows or columns are eliminated at once in a 2P game + code:GXXOZGVT+GZKPGZVT + +cartridge sha256:7026334a7e8742b61b450f4b3b182922c6a69fc723d7cd19c83db365f15e45ba + title:Duck Hunt (World) + cheat + description:Infinite ammo + code:SZNIPPVG + cheat + description:Hit anywhere + code:AAXSGZSY + cheat + description:Always get the perfect bonus + code:AASIAUZA+ALSIPLEI + cheat + description:Ducks never fly away - Game A + code:IAVKKZVG + cheat + description:Enable game "D" (hit select three times) + code:GEOKTPLA + cheat + description:Infinite ammo (alt) + code:00BA:03 + +cartridge sha256:262c1fcacd30a7f3018bd33ea6cf3fb86f8d9a77273d4f822268bff2c7deeb9a + title:Duck Maze (Australia) (Unl) + cheat + description:Invincibility + code:SXUUVLAX + cheat + description:No breaking eggs from falling + code:AEEUEUZZ + +cartridge sha256:8ba8baed01a9fbaf1e9ff29e0c9825db1963ac2aff211d6f1f3bcfd3839e2013 + title:DuckTales (USA) + cheat + description:Invincibility + code:EISVZLEY+EIEEGAEY + cheat + description:Infinite health + code:ATVVXLEZ + cheat + description:Infinite health (alt) + code:AANVSLPA + cheat + description:Infinite lives + code:SXUIEKVK + cheat + description:Infinite time + code:OVUVAZSV + cheat + description:Lose half normal health (in easy game) + code:LAVTNLPA + cheat + description:Double usual time + code:ZAXSKLIE+SXNIUKOU+SZNISESU + cheat + description:Multi-jump + code:EUOTYULU+UVXVALVT+AOUVILEY+NAETLKLL+GXOTPTEY + cheat + description:Walk 2x faster + code:ZEOVYGPA + cheat + description:Walk 4x faster + code:GEOVYGPA + cheat + description:Start with 1 life + code:AAESULZA + cheat + description:Start with 6 lives + code:IAESULZA + cheat + description:Start with 9 lives + code:AAESULZE + cheat + description:Invincibility (star effect) + code:0075:01 + cheat + description:Invincibility (blinking) + code:007D:FA + cheat + description:Infinite health (alt) + code:0342:00+0346:00+034A:00 + cheat + description:Infinite time (one's digit) + code:0159:09 + cheat + description:Infinite time (ten's digit) + code:0155:09 + cheat + description:Infinite time (hundred's digit) + code:0151:09 + cheat + description:All levels cleared except the Amazon + code:00A0:1E + cheat + description:Have the Skeleton Key, Mine Key and Remote Control + code:00A1:01+00A3:FF + cheat + description:Have $9,000,000 + code:0324:09 + +cartridge sha256:54c70628739c9cfab40b8d79555e9076adae34127ef369988ca91635b4a688bf + title:DuckTales 2 (USA) + cheat + description:Invincibility + code:ESOTVAEY + cheat + description:Infinite health + code:SZONTZSA + cheat + description:Infinite lives + code:GZXGZGVG + cheat + description:Infinite lives (alt) + code:SGXGZGVG + cheat + description:Take more damage + code:APONPXAA + cheat + description:Take less damage + code:GAONPXAA + cheat + description:Take very little damage + code:ZAONPXAA + cheat + description:Have lots of money + code:PAXSPZAA + cheat + description:$5,000 cash from small diamonds + code:IEKSPLPA + cheat + description:$9,000 cash from small diamonds + code:PEKSPLPE + cheat + description:Start with full energy + code:ASNKPAAL + cheat + description:Start with a lot less energy + code:AONKPAAL + cheat + description:Start with 1 life + code:AAEKAPZA + cheat + description:Start with 6 lives + code:IAEKAPZA + cheat + description:Start with 9 lives + code:AAEKAPZE + +cartridge sha256:12c92261dfae9c01ce0172cd1e7d70192105ceb350b37c3f1cb2c72f9a10a6b9 + title:Dudes with Attitude (USA) (Rev 1) (Unl) + cheat + description:Infinite energy + code:SLUSSIVI + cheat + description:Infinite time + code:SZUSIYVG + +cartridge sha256:99bba29bd92942f64d8a0beda7df3d8bff1ddcebcd3172eec16009fcb4a8bd3e + title:Dudes with Attitude (USA) (Unl) + cheat + description:Infinite energy + code:SLUSSIVI + cheat + description:Infinite time + code:SZUSIYVG + +cartridge sha256:c613c10e32b93dbc402356273d698efa14814a51b0339d6d7aacdfb639a7acd7 + title:Dungeon Magic - Sword of the Elements (USA) + cheat + description:Take no damage except from scorpions + code:SXVLTLSA + cheat + description:Take less damage + code:OVVLGLSV+ZEVLIUYL + cheat + description:Stay at the Inn for free + code:PXSTLZPG+AXSTYZAG + cheat + description:Items at Grocer's shop are free + code:PXUVXTPG+AXUVVTAG + cheat + description:Items at Armory are free + code:PXENPLPG+AXENILAG + cheat + description:Start with 100 gold pieces + code:GTKIITAA + cheat + description:Start with 512 gold pieces + code:ZAKIITAA+PGKSGTAG + +cartridge sha256:690ec2de233486d9fdb1e096ca4aa07aa6e764b0d6d6417454d0a770c875078d + title:Dynowarz - Destruction of Spondylus (USA) + cheat + description:Mostly invincible + code:PANSAEPX+GZNITAVG + cheat + description:Infinite shield + code:AVNTNKXA + cheat + description:No harm from spikes + code:ATSIOGSZ + cheat + description:No harm from any dinosaur + code:AAVNVPLA + cheat + description:Mega-jump power + code:YEXIYLLA + cheat + description:Speed up left and right + code:LANSIZPA + cheat + description:Start on level 2 + code:TAXGLPPA + cheat + description:Start on level 3 + code:ZAXGLPPE + cheat + description:Start on level 4 + code:TAXGLPPE + cheat + description:Start on level 5 + code:ZPXGLPPA + +cartridge sha256:7951287af48ef9f2e2b375934acff99fe1543aea39d2729d2863b38ab498e231 + title:Egypt (Japan) + cheat + description:Infinite power-ups + code:OUEPXNOO + cheat + description:No steps + code:SXVAULVT+SXVANLVT + cheat + description:No rotates + code:SZEANGVT+SZEAUGVT + +cartridge sha256:e2824a71c74106326013915d9f8a67be22c367599feefd8da6538f62d5e6f5b0 + title:Elevator Action (USA) + cheat + description:Infinite lives - P1 + code:GXEUOUVK + cheat + description:Can only shoot one bullet + code:GASTLPTA + cheat + description:Slower man + code:PESIAYLA+NNUSZNSN + cheat + description:Faster man + code:IESIAYLA+XNUSZNSN + cheat + description:Faster bullets + code:ZAVTLOAE+VYVTYOEY + cheat + description:Slower bullets + code:GAVTLOAA+KYVTYOEN + cheat + description:Faster enemy + code:GEONGPZA+XNXNGOVN + cheat + description:Slower enemy + code:PEONGPZA+NNXNGOVN + cheat + description:Start with 1 life - P1 + code:AAULNLZA + cheat + description:Start with 6 lives - P1 + code:IAULNLZA + cheat + description:Start with 9 lives - P1 + code:AAULNLZE + cheat + description:Start with 6 lives - P2 + code:IEVUULZA + cheat + description:Start with 9 lives - P2 + code:AEVUULZE + +cartridge sha256:9d0396286f2c027367422b8347216a309200a21b019939f08a7c457c7c4c918d + title:Eliminator Boat Duel (USA) + cheat + description:Almost infinite nitros - no on buoy stage + code:SZVSVNVS + cheat + description:Boat starts with full turbo, steering, hull, max engine power + code:IENEYPPA + cheat + description:Have full hull strength + code:SXUGOEVS + cheat + description:Computer boat goes crazy + code:KAAISZ + cheat + description:Start with 0 nitros + code:AAEEZZGA + cheat + description:Start with 36 nitros + code:IZEEZZGA + +cartridge sha256:761df2c2e04f9ffec5eec59afd821bd74af3b155546519d649876aad37160c06 + title:Esper Dream 2 - Aratanaru Tatakai (Japan) + cheat + description:Infinite HP + code:SZNIIGSA + cheat + description:Infinite ESP + code:SZUTEPSA + cheat + description:Quick level up + code:AEXIYVPE + cheat + description:Chests worth lots of gold + code:AEXOSTPA + +cartridge sha256:e9f4c9d1b7c66c6af83f2db5d4f704cf5f4b3c86e26a49c05539237807d8875e + title:Excitebike (Japan, USA) + cheat + description:Never crash + code:SZOSKTSP + cheat + description:Never crash when holding forward + code:ATSVIASP+ATVTLASP+ATVSUGSP + cheat + description:Never lose speed (even if you crash) + code:SLNKSTVI + cheat + description:Never overheat + code:SXXTYUVV + cheat + description:Recover fast after crashes + code:YEXIKOYA + cheat + description:Reduced enemy bikes in game B + code:PEXIEZLA + cheat + description:Timer runs at half speed + code:AAUSEYAO + cheat + description:Timer runs at quarter speed + code:GAUSEYAP + cheat + description:Turbo speed on button A + code:ENUKGEAP+GESGPALA + cheat + description:Mega turbo speed on button A + code:EVUKGEAP+TESGPALA + cheat + description:Infinite obstacles in design mode + code:AAEYSAPA + cheat + description:Start racing before gate opens + code:AAEVXXAL+AAXGXSIP+AAXSOXYL+APUSOTEI + cheat + description:Press Start to complete current race (uses your race position for the verdict) + code:AASKOZLA+ZISKEZOL + +cartridge sha256:9e3c5574e31cbf74146808df930a70856d7196ec581e40cae3061743504bfba2 + title:Exodus - Journey to the Promised Land (USA) (v4.0) (Unl) + cheat + description:Infinite lives + code:SZUZKAVI + cheat + description:Infinite time + code:SXNSKIVG + +cartridge sha256:e9aab85fd91822b9dc7a89997eda3415e45a07fe21580c0df4765ce392e63824 + title:F-1 Race (Japan) + cheat + description:Invincibility + code:ATOTPGVT + cheat + description:Infinite time + code:SAUSTPVG + cheat + description:Don't lose speed when driving over grass/dirt + code:SXXIIZSA+SXXSLZSA + cheat + description:Don't lose speed when skidding in the road + code:SXEKYLSA + +cartridge sha256:3fd39ba2cdd6e220b07050d752a2c67d4a0f16a72ea9e519adf7390721cd9bdd + title:F15 City War (USA) (v1.1) (Unl) + cheat + description:Infinite lives + code:00E4:09 + +cartridge sha256:0e3db714b82795111afa386f32534ece968d0f8ccb63dc70189d2010dc77a2a7 + title:F15 City War (USA) (v1.0) (Unl) + cheat + description:Infinite lives + code:00E4:09 + +cartridge sha256:bf4b9f8706814e9164971a3c32535bb2ec718232cf05decda785770fa949d396 + title:F-15 Strike Eagle (USA) + cheat + description:Infinite type 1 missiles + code:004A:09 + cheat + description:Infinite type 2 missiles + code:004B:09 + cheat + description:Infinite type 3 missiles + code:004C:09 + cheat + description:Billions of points + code:0171:09 + +cartridge sha256:69bc9f0a2f0cd50d624fafced0051056fd91816f0593719678a42c8637622426 + title:F-117A - Stealth Fighter (USA) + cheat + description:Invincibility + code:SXXOATSA + cheat + description:Invincibility (alt) + code:0026:00 + cheat + description:Infinite AAM Missiles + code:001F:63 + cheat + description:Infinite AGM Missiles + code:0020:63 + cheat + description:Infinite Flares + code:0021:63 + cheat + description:Infinite Chaff + code:0022:63 + cheat + description:Have 5 million+ points + code:0175:FF + +cartridge sha256:0de5af54fd433bc6678cd8c62b5e6f0a0987c26d64b2081764e66263cf0c658c + title:Family Feud (USA) + cheat + description:Infinite time to answer a question + code:SXKKESVK + cheat + description:10 strikes allowed + code:ZESOGALE + +cartridge sha256:e0b124ddd8ac7be9e0f0b14679a089c475646fe97425fea36674d75a0f481461 + title:Fantastic Adventures of Dizzy, The (USA) (Unl) + cheat + description:Infinite lives + code:SXVIAAVG + cheat + description:Spiders, bats, ants and rats do no damage + code:AAVYPXAA + cheat + description:Play bubble sub-game only + code:YYUZPSTE + cheat + description:Play river sub-game only + code:TYUZPSTE + cheat + description:Play mine sub-game only + code:IYUZPSTE + cheat + description:Play puzzle sub-game ony + code:ZYUZPSTE + cheat + description:Start with 10 stars instead of 100 + code:ZEKYVZGV + cheat + description:Start with 10 lives + code:PAOAZAZE + +cartridge sha256:ad14301747e0ae0f9b941c6002102d69916ca5e87b355156ab79311ce8dd7236 + title:Fantasy Zone (USA) (Unl) + cheat + description:Infinite lives + code:OZEVYTVK + cheat + description:Keep bought weapon for a life + code:OXETOAVK + cheat + description:Keep bought weapon until next shop visit + code:OXETOAVK+OGOVATSE + cheat + description:Autofire on all weapons + code:AAOVKTPA + cheat + description:Start with 1 life + code:PAXVOPLA + cheat + description:Start with 6 lives + code:TAXVOPLA + cheat + description:Start with 9 lives + code:PAXVOPLE + cheat + description:Start on level 2 + code:PASVYYAA + cheat + description:Start on level 3 + code:ZASVYYAA + cheat + description:Start on level 4 + code:LASVYYAA + cheat + description:Start on level 5 + code:GASVYYAA + cheat + description:Start on level 6 + code:IASVYYAA + cheat + description:Start on level 7 + code:TASVYYAA + +cartridge sha256:6f23f245b9edc5af0c07fab9e12f5c0571ea0f52413e4ce6ad36e2f57ddf4097 + title:Faria - A World of Mystery & Danger! (USA) + cheat + description:Infinite HP + code:SAOEGPST+SEUUEAST + cheat + description:Infinite batteries + code:SZXGINVK + cheat + description:Infinite Bombs + code:SXOLYOVK + cheat + description:Infinite Sede magic + code:GXSAASVK + cheat + description:Infinite Saba magic + code:GXNEZSVK + cheat + description:Get 250 arrows when buying any amount of arrows + code:AAVZSPZA + cheat + description:Don't get charged in shops for items you can afford + code:GZXXZUSE+GZXXYUSE+GZUZGUSE + +cartridge sha256:58f2ba801354a8e5b32e7d1cbcc740b8dc838e7d48c3d2f3eedea36b49b1a518 + title:Faxanadu (USA) (Rev A) + cheat + description:Infinite P (health) + code:GXOGZESV+GXOKLESV + cheat + description:Infinite M (magic) + code:AEENEZZA + cheat + description:Infinite Gold + code:SXXNUOSE+SXUYUOSE+SXUNUOSE + cheat + description:Jump in direction you are facing + code:AVXVGPSZ + cheat + description:Slow mode + code:AAUTAEOY+AAKTPAKY+AAUTZAPA + cheat + description:Start with double P (health) + code:AXXSNTAP + cheat + description:Start with triple P (health) + code:AUXSNTAP + cheat + description:Start with half normal amount of Gold + code:IASEPSZA + cheat + description:Start with double normal amount of Gold + code:GPSEPSZA + cheat + description:Invincibility + code:00AD:48 + cheat + description:Infinite P (health) (alt) + code:0431:55 + cheat + description:Infinite M (magic) (alt) + code:039A:50 + cheat + description:Infinite Gold (alt) + code:0394:FF + cheat + description:Have Wing Boots ability (hold up and A) + code:0429:0A + cheat + description:Walk faster + code:00AA:02 + +cartridge sha256:52f7e7309f1f53f632912182f3a65f574c949392ab92f55c2494a7e648ef5ccb + title:Faxanadu (USA) + cheat + description:Infinite P (health) + code:GXOGZESV+GXOKLESV + cheat + description:Infinite M (magic) + code:AEENEZZA + cheat + description:Infinite Gold + code:SXXNUOSE+SXUYUOSE+SXUNUOSE + cheat + description:Jump in direction you are facing + code:AVXVGPSZ + cheat + description:Slow mode + code:AAUTAEOY+AAKTPAKY+AAUTZAPA + cheat + description:Start with double P (health) + code:AXXSNTAP + cheat + description:Start with triple P (health) + code:AUXSNTAP + cheat + description:Start with half normal amount of Gold + code:IASEPSZA + cheat + description:Start with double normal amount of Gold + code:GPSEPSZA + cheat + description:Invincibility + code:00AD:48 + cheat + description:Infinite P (health) (alt) + code:0431:55 + cheat + description:Infinite M (magic) (alt) + code:039A:50 + cheat + description:Infinite Gold (alt) + code:0394:FF + cheat + description:Have Wing Boots ability (hold up and A) + code:0429:0A + cheat + description:Walk faster + code:00AA:02 + +cartridge sha256:884b46ad4eb5160a94c19e8954846d644be36803efc53c977e99b1342886cc6b + title:Felix the Cat (USA) + cheat + description:Infinite time + code:SUNNGNSO + cheat + description:Infinite lives + code:AEUYKPPA + cheat + description:Hearts can't be replenished from bottles + code:AAEENAZA + cheat + description:Bottles replenish more hearts + code:GAEENAZA + cheat + description:Bottles replenish even more hearts + code:AAEENAZE + cheat + description:1 Felix icon gives 2 + code:ZAOSOZPA+APNSOXPO + cheat + description:Start with 9 lives + code:APUGAGZO + cheat + description:Start with 6 lives + code:IPUGAGZP + cheat + description:Start with 1 life + code:APUGAGZP + cheat + description:Invincibility (blinking) + code:03CD:03 + cheat + description:Infinite lives (alt) + code:03A6:19 + cheat + description:Infinite special + code:03C0:0A + cheat + description:Have 99 Felix icons + code:03A7:19+03A8:19 + cheat + description:Play as Magic/Balloon Felix + code:03C6:01 + cheat + description:Play as Buggy/Plane Felix + code:03C6:02 + cheat + description:Play as Tank Felix + code:03C6:03 + +cartridge sha256:c0c98471130cd09c82af6ead5e706c9299cc2cb4584016a5e5eb0c8897380172 + title:Fester's Quest (USA) + cheat + description:Invincibility + code:AYIPOG + cheat + description:Infinite health + code:XVEPUKVK + cheat + description:Infinite Invisible Potions on pick-up + code:SZEIYOVK + cheat + description:Infinite Missiles on pick-up + code:SZVVXUVK + cheat + description:Infinite Money + code:SZUSYOSE + cheat + description:Infinite Nooses on pick-up + code:SXUITEVK + cheat + description:Infinite Potions on pick-up + code:SXVSLEVK + cheat + description:Infinite T.N.T on pick-up + code:SZNIYOVK + cheat + description:Infinite Vice Grips on pick-up + code:SXSITEVK + cheat + description:Invincibility (alt) + code:04F8:C0 + cheat + description:Infinite health (alt) + code:04E5:03+04E9:03 + cheat + description:Max health + code:04EA:04 + cheat + description:Have level 8 Gun + code:04E7:08 + cheat + description:Have level 4 Whip + code:04E8:04 + cheat + description:Infinite Bulbs + code:015C:64 + cheat + description:Infinite Invisible Potions + code:0161:64 + cheat + description:Infinite Keys + code:015D:64 + cheat + description:Infinite Money (alt) + code:0162:64 + cheat + description:Infinite Missiles + code:0163:64 + cheat + description:Infinite Nooses + code:015E:64 + cheat + description:Infinite Potions + code:0160:64 + cheat + description:Infinite T.N.T + code:0164:64 + cheat + description:Infinite Vice Grips + code:015F:64 + +cartridge sha256:179bd9c16fc5b85168fecac685045ed58f6bec5a51363babb7aaaaceb6fa0932 + title:Fighting Road (Japan) + cheat + description:Infinite health + code:SXESLTSA + +cartridge sha256:2ae778c5a59fac650fa97e93d883381dbf96c5a0ad2c1db94fd822663904f7e5 + title:Final Combat (Asia) (PAL) (Unl) + cheat + description:Infinite health + code:SXSZAVSE+SXOGGNSE + cheat + description:Infinite lives + code:SZVLOLVI + cheat + description:Infinite time + code:SZNOOSVK + +cartridge sha256:fa456d852372173ea31b192459ba1a2026f779df67793327ba6e132476c1d034 + title:Final Fantasy (USA) + cheat + description:Almost infinite Gold + code:GXSZPKSV+GXSXZKSV + cheat + description:999999+ Gold + code:NYOUTAAE + cheat + description:Non-magic users can use level 1 magic + code:ELEXVLEY+AESGANGA+AESGGNAA + cheat + description:LIFE spell never uses up Magic Points + code:SZULIEVS + cheat + description:LIF2 spell never uses up Magic Points + code:SZVULEVS + cheat + description:Magic users start with 6 Magic Points + code:TESGTYZA + cheat + description:Magic users start with 9 Magic Points + code:PESGTYZE + cheat + description:No random battles (enable at start of game) + code:OOTPVP + cheat + description:Double Fighter's Hit Points (enable at start of game) + code:TGKLPALZ + cheat + description:Double Fighter's Hit (enable at start of game) + code:GPKUAEZA + cheat + description:Double Fighter's Evade (enable at start of game) + code:ZTKUPAIU + cheat + description:Double Fighter's Luck (enable at start of game) + code:ZAKLTAIE + cheat + description:Double Thief's Hit Points (enable at start of game) + code:GLSLPETO + cheat + description:Triple Thief's Damage (enable at start of game) + code:TASLYAZA + cheat + description:Double Thief's Hit (enable at start of game) + code:ZASUAAIE + cheat + description:Double Thief's Evade (enable at start of game) + code:GYSUPEZL + cheat + description:Double Thief's Luck (enable at start of game) + code:TPSLTEYE + cheat + description:Double Black Belt's Hit Points (enable at start of game) + code:ZGVLPAPZ + cheat + description:Triple Black Belt's Damage (enable at start of game) + code:TAVLYAZA + cheat + description:Double Black Belt's Hit (enable at start of game) + code:ZAVUAAIE + cheat + description:Double Black Belt's Evade (enable at start of game) + code:ZTVUPAIU + cheat + description:Double Black Belt's Luck (enable at start of game) + code:ZAVLTAIE + cheat + description:Double Red Mage's Hit Points (enable at start of game) + code:GLNLPETO + cheat + description:Double Red Mage's Damage (enable at start of game) + code:ZANLYAIE + cheat + description:Double Red Mage's Hit (enable at start of game) + code:TANUAAYE + cheat + description:Double Red Mage's Evade (enable at start of game) + code:GYNUPEZL + cheat + description:Double Red Mage's Luck (enable at start of game) + code:ZANLTAIE + cheat + description:Double White Mage's Hit Points (enable at start of game) + code:AUELPEGO + cheat + description:Triple White Mage's Damage (enable at start of game) + code:TEELYAZA + cheat + description:Double White Mage's Hit (enable at start of game) + code:ZEEUAAIE + cheat + description:Double White Mage's Evade (enable at start of game) + code:ZVEUPAIU + cheat + description:Double White Mage's Luck (enable at start of game) + code:ZEELTAIE + cheat + description:Double Black Mage's Hit Points (enable at start of game) + code:ZUOLPEPP + cheat + description:Triple Black Mage's Damage (enable at start of game) + code:LEOLYAPA + cheat + description:Double Black Mage's Hit (enable at start of game) + code:ZEOUAAIE + cheat + description:Double Black Mage's Evade (enable at start of game) + code:GNOUPEZL + cheat + description:Double Black Mage's Luck (enable at start of game) + code:GOOLTEZA + cheat + description:Start with 800 Gold + code:AZOUGAEP+LAOUIAPA + cheat + description:More enemies, more difficult + code:6D8D:99 + cheat + description:No random battles (alt) + code:00F5:FF + cheat + description:Have Adamant + code:6027:01 + cheat + description:Have Bottle + code:602F:01 + cheat + description:Have Canoe + code:6031:01 + cheat + description:Have Chime + code:602C:01 + cheat + description:Have Crown + code:6022:01 + cheat + description:Have Crystal + code:6023:01 + cheat + description:Have Cube + code:602E:01 + cheat + description:Have Floater + code:602B:01 + cheat + description:Have Herb + code:6024:01 + cheat + description:Have Key + code:6025:01 + cheat + description:Have Lute + code:6021:01 + cheat + description:Have Oxyale + code:6030:01 + cheat + description:Have Rod + code:602A:01 + cheat + description:Have Ruby + code:6029:01 + cheat + description:Have Slab + code:6028:01 + cheat + description:Have Tail + code:602D:01 + cheat + description:Have TNT + code:6026:01 + cheat + description:Have first Crystal lit + code:6032:01 + cheat + description:Have second Crystal lit + code:6033:01 + cheat + description:Have third Crystal lit + code:6034:01 + cheat + description:Have last Crystal lit + code:6035:01 + cheat + description:Character 1 - 255 HP + code:610A:FF + cheat + description:Character 1 - 99 STR + code:6110:63 + cheat + description:Character 1 - 99 AGL + code:6111:63 + cheat + description:Character 1 - 99 INT + code:6112:63 + cheat + description:Character 1 - 99 VIT + code:6113:63 + cheat + description:Character 1 - 99 Luck + code:6114:63 + cheat + description:Character 1 - 255 Damage + code:6120:FF + cheat + description:Character 1 - 255 Hit % + code:6121:FF + cheat + description:Character 1 - 255 Absorb + code:6122:FF + cheat + description:Character 1 - 255 Evade % + code:6123:FF + cheat + description:Character 1 - Infinite level 1 magic use + code:6320:08+6328:08 + cheat + description:Character 1 - Infinite level 2 magic use + code:6321:08+6329:08 + cheat + description:Character 1 - Infinite level 3 magic use + code:6322:08+632A:08 + cheat + description:Character 1 - Infinite level 4 magic use + code:6323:08+632B:08 + cheat + description:Character 1 - Infinite level 5 magic use + code:6324:08+632C:08 + cheat + description:Character 1 - Infinite level 6 magic use + code:6325:08+632D:08 + cheat + description:Character 1 - Infinite level 7 magic use + code:6326:08+632E:08 + cheat + description:Character 1 - Infinite level 8 magic use + code:6327:08+632F:08 + cheat + description:Character 2 - 255 HP + code:614A:FF + cheat + description:Character 2 - 99 STR + code:6150:63 + cheat + description:Character 2 - 99 AGL + code:6151:63 + cheat + description:Character 2 - 99 INT + code:6152:63 + cheat + description:Character 2 - 99 VIT + code:6153:63 + cheat + description:Character 2 - 99 Luck + code:6154:63 + cheat + description:Character 2 - 255 Damage + code:6160:FF + cheat + description:Character 2 - 255 Hit % + code:6161:FF + cheat + description:Character 2 - 255 Absorb + code:6162:FF + cheat + description:Character 2 - 255 Evade % + code:6163:FF + cheat + description:Character 3 - 255 HP + code:618A:FF + cheat + description:Character 3 - 99 STR + code:6190:63 + cheat + description:Character 3 - 99 AGL + code:6191:63 + cheat + description:Character 3 - 99 INT + code:6192:63 + cheat + description:Character 3 - 99 VIT + code:6193:63 + cheat + description:Character 3 - 99 Luck + code:6194:63 + cheat + description:Character 3 - 255 Damage + code:61A0:FF + cheat + description:Character 3 - 255 Hit % + code:61A1:FF + cheat + description:Character 3 - 255 Absorb + code:61A2:FF + cheat + description:Character 3 - 255 Evade % + code:61A3:FF + cheat + description:Character 4 - 255 HP + code:61CA:FF + cheat + description:Character 4 - 99 STR + code:61D0:63 + cheat + description:Character 4 - 99 AGL + code:61D1:63 + cheat + description:Character 4 - 99 INT + code:61D2:63 + cheat + description:Character 4 - 99 VIT + code:61D3:63 + cheat + description:Character 4 - 99 Luck + code:61D4:63 + cheat + description:Character 4 - 255 Damage + code:61E0:FF + cheat + description:Character 4 - 255 Hit % + code:61E1:FF + cheat + description:Character 4 - 255 Absorb + code:61E2:FF + cheat + description:Character 4 - 255 Evade % + code:61E3:FF + +cartridge sha256:7ff89b50156b6f5b3d78d3d2eeec8a9221d9f7b18f8350abf89b7867a205f710 + title:Final Fantasy III (Japan) + cheat + description:Infinite capacity points. You still have to have enough points to make the job change, but no points will be subtracted from your total + code:SXOXUUSE + cheat + description:All items in shops are free. You must have enough to cover the item, but will not be charged + code:XVULAASV + cheat + description:Knife casts a FIRE spell when used as a item in battle + code:PUNPGKYY + cheat + description:Knife casts a FIRE3 spell when used as a item in battle + code:TENPGKYN + cheat + description:Knife casts a BOLT3 spell when used as a item in battle + code:IONPGKYY + cheat + description:Knife casts a ICE3 spell when used as a item in battle + code:IONPGKYN + cheat + description:Knife casts a DEATH spell when used as a item in battle + code:PENPGKYY + cheat + description:Knife casts a METEO spell when used as a item in battle + code:ZENPGKYY + cheat + description:Knife casts a HEAL spell when used as a item in battle + code:LENPGKYN + cheat + description:Knife casts a CURE4 spell when used as a item in battle + code:ZENPGKYN + cheat + description:Dagger casts a FIRE3 spell when used as a item in battle + code:TENOGKYN + cheat + description:Dagger casts a BOLT3 spell when used as a item in battle + code:IONOGKYY + cheat + description:Dagger casts a ICE3 spell when used as a item in battle + code:IONOGKYN + cheat + description:Dagger casts a DEATH spell when used as a item in battle + code:PENOGKYY + cheat + description:Dagger casts a METEO spell when used as a item in battle + code:ZENOGKYY + cheat + description:Dagger casts a HEAL spell when used as a item in battle + code:LENOGKYN + cheat + description:Dagger casts a CURE4 spell when used as a item in battle + code:ZENOGKYN + cheat + description:Long Sword casts a FIRE3 spell when used as a item in battle + code:TAXPGSYN + cheat + description:Long Sword casts a BOLT3 spell when used as a item in battle + code:IPXPGSYY + cheat + description:Long Sword casts a ICE3 spell when used as a item in battle + code:IPXPGSYN + cheat + description:Long Sword casts a DEATH spell when used as a item in battle + code:PAXPGSYY + cheat + description:Long Sword casts a METEO spell when used as a item in battle + code:ZAXPGSYY + cheat + description:Long Sword casts a HEAL spell when used as a item in battle + code:LAXPGSYN + cheat + description:Long Sword casts a CURE4 spell when used as a item in battle + code:ZAXPGSYN + +cartridge sha256:5f21fadd084947d11224d1f37218a504bd75f7c6f17212f638a6917ba8a96f99 + title:Fire Bam (FDS) + cheat + description:All fire items worth 65,535 + code:NYEPXZAE + cheat + description:Start with 65,534 Fire + code:VNKIKYOE+NNKISNPE + +cartridge sha256:9a0cc935c7d8452eff5b90f591bb6390d04362545ecd66b4be67a875ad63dc73 + title:Fire Dragon (Asia) (Unl) + cheat + description:One fireball needed to finish the level + code:034F:04 + cheat + description:Start on stage 50 + code:034D:32 + +cartridge sha256:3f5ed8b5207ff10ef490e7533bdd8419e5266101d4049d7689c01b5b352a4547 + title:Fire Hawk (USA) (Unl) + cheat + description:Invincibility + code:OZOXOTES + cheat + description:Start with 1 life + code:PAOEPALA + cheat + description:Start with 6 lives + code:TAOEPALA + cheat + description:Start with 9 lives + code:PAOEPALE + cheat + description:Infinite Missiles + code:04DA:1F + cheat + description:Infinite ammo + code:04DC:1F + cheat + description:Infinite fuel + code:04F4:26 + +cartridge sha256:04264565cf33f4bd1b23a3f7a1be1487a548c7f6b85323c68af754b0927b0a56 + title:Fist of the North Star (USA) + cheat + description:Invincibility + code:SXXGAIAX + cheat + description:Infinite health + code:SZSGUGSA + cheat + description:Infintie time + code:SZSVGTVG + cheat + description:Infinite lives + code:SXKKYPVG + cheat + description:One hit kills you + code:OTSGOGSV + cheat + description:Sweep kick damages enemies more + code:TEELTPPA + cheat + description:Straight kick damages enemies more + code:AEOLGPLE + cheat + description:Can't be knocked back by big thugs + code:AAUKVGGA + cheat + description:Pogo stick + code:EISGUPEY + cheat + description:Take minimum damage from all enemies + code:OTSGOGSV+PASGXKOI + cheat + description:Any attack mega-damages enemies + code:OVOUZPSV+ZEOULOOS + cheat + description:Start with 1 life + code:PEKKGALA + cheat + description:Start with 6 lives + code:TEKKGALA + cheat + description:Start with 9 lives + code:PEKKGALE + cheat + description:Invincibility (blinking) + code:0066 01 + cheat + description:Infinite health (alt) + code:0073:38 + cheat + description:Infinite time (alt) + code:0065 09 + cheat + description:Infinite power + code:006C 07 + cheat + description:Infinite Bomb + code:0063 07 + +cartridge sha256:6e5bdfe7ee4cc4d949ea80016dbfb2b4322bbe193b5f28483ce7009e506efe40 + title:Flight of the Intruder (USA) + cheat + description:Infinite radar-guided missiles - bombing/strafing screen + code:GZUOZYVG + cheat + description:Start with 9 radar-guided missiles - bombing/strafing screen + code:PAOALZTE + cheat + description:Infinite missiles - cockpit screen + code:GZUOLKVK + cheat + description:Start each mission with 6 missiles + code:OZKZTXOK+AAKXGZPA + cheat + description:Start on mission 3 + code:GAKGKGAA + cheat + description:Start on mission 6 + code:ZAKGKGAE + cheat + description:Start on mission 9 + code:APKGKGAA + cheat + description:Start on mission 12 + code:TPKGKGAA + +cartridge sha256:3036a59bb7bf16a3b80c94750bccaa35be9ab5cd94f99d68d3979ec53cd42c03 + title:Flintstones, The - The Rescue of Dino & Hoppy (USA) + cheat + description:Invincibility + code:AVOPZOVG + cheat + description:Infinite lives + code:SXOAAEVK + cheat + description:Infinite energy (hearts) + code:SZNTZKVK+SXOPZOVK + cheat + description:15 coins on pick-up + code:YESTZZIE + cheat + description:2 coins on pick-up + code:ZESTZZIA + cheat + description:Slingshot doesn't use up coins + code:AAUAXTLA + cheat + description:Axe doesn't use up coins + code:AAUAUTLA + cheat + description:Bomb doesn't use up coins + code:AAUAKVZA + cheat + description:Infinite Firepower + code:AETEKI + cheat + description:Max power charge + code:LOKOEPPA+LPEZLPPA+LOEPLPPA+LPUOLZPA + cheat + description:Start with Slingshot + code:PEEAAPAA + cheat + description:Start with Axe + code:ZEEAAPAA + cheat + description:Start with Bomb + code:GEEAAPAA + cheat + description:Start with 1 life + code:AAVAYPZA + cheat + description:Start with 6 lives + code:IAVAYPZA + cheat + description:Start with 9 lives + code:AAVAYPZE + cheat + description:Start with 99 coins + code:LTNELOZA + cheat + description:Infinite energy (hearts) (alt) + code:0308:03 + cheat + description:Infinite lives + code:0305:09 + cheat + description:Infinite Coins + code:030B:FF + cheat + description:Max power charge (alt) + code:0312:0C + cheat + description:One hit kills on most bosses + code:03D7:00 + +cartridge sha256:8da82a28be164453d1f8aa293fc8b02aaede397b52622a14ead331e475e5ca2f + title:Flintstones, The - The Surprise at Dinosaur Peak! (USA) + cheat + description:Invincibility + code:AVEPKOSA + cheat + description:Infinite lives + code:SXEETEVK + cheat + description:Infinite energy + code:AANONPPA + cheat + description:Infinite energy (alt) + code:SXEPKOSE + cheat + description:Infinite stone hammers on pick-up + code:SXXOUVSE + cheat + description:Enemies do more damage (3 hearts) + code:LANONPPA + cheat + description:Get bowling ball instead of stone hammer + code:ZEEEUYPA + cheat + description:Get mystery item instead of stone hammer + code:LEEEUYPA + cheat + description:Continue on Level 2 + code:PAKAVPAA + cheat + description:Continue on Level 3 + code:ZAKAVPAA + cheat + description:Continue on Level 4 + code:LAKAVPAA + cheat + description:Continue on Level 5 + code:GAKAVPAA + cheat + description:Continue on Level 6 + code:IAKAVPAA + cheat + description:Continue on Level 7 + code:TAKAVPAA + cheat + description:Continue on Level 8 + code:YAKAVPAA + cheat + description:Continue on Level 9 + code:AAKAVPAE + cheat + description:Continue on Level 10 + code:PAKAVPAE + cheat + description:Start with max power + code:GOEATOGA + cheat + description:Start with 1 heart + code:PANELPLA + cheat + description:Start with 2 hearts + code:ZANELPLA + cheat + description:Start with 6 hearts + code:TANELPLA + cheat + description:Start with 9 hearts + code:PANELPLE + cheat + description:Start with 1 life instead of 3 + code:AASALPZA + cheat + description:Start with 5 lives + code:GASALPZA + cheat + description:Start with 9 lives + code:AASALPZE + cheat + description:Start on level 2 + code:VTNEXOSE + +cartridge sha256:fd7523b5ec5769e4d782a9699a2253bd15d0036111b8ed26195238b35b74257d + title:Flying Dragon - The Secret Scroll (USA) + cheat + description:Start with infinite lives + code:VEKLTAKZ + cheat + description:Start with infinite time + code:GXEEEPVG + cheat + description:Start with double KO power + code:TAOXULLA + cheat + description:Start with 1 life + code:PANATALA + cheat + description:Start with 6 lives + code:TANATALA + cheat + description:Start with 9 lives + code:PANATALE + +cartridge sha256:5e2db0db6b1d3d7fe1630a6bab38a66081e3266070a4dfac9c3ace9edf39375e + title:Flying Hero (Japan) + cheat + description:Finish levels automatically + code:03A9:00 + cheat + description:Infinite lives + code:0400:03 + cheat + description:Max Bounce + code:04B0:03 + cheat + description:One hit kills on Fires + code:0510:80 + +cartridge sha256:1568e77e6533087eee26f952b0f58373fc5e56c4b2139023dbfdadc0828249c8 + title:Flying Warriors (USA) + cheat + description:Infinite life + code:SXNKIKSE + cheat + description:Infinite lives + code:SZVGKOVK + cheat + description:Infinite KO's + code:SXOZPKSE+SZSKLXSE + cheat + description:Infnite credits + code:SZXEZZVG + +cartridge sha256:eedcf3fae4fe66102a1bf1338a1ea3276f5aadb3c3bc5770dd1d260e2fc44bac + title:Formation Z (Japan) + cheat + description:Invincibility + code:SZOOTVSE+SZSXPESE+SZSXAKSE+SXXXVUSE+SXEPXNSE+SZVOTNSE+SXOXSXSE+SXUZONSE+SXNXKSSE+SZXOPVSE + cheat + description:Infinite fuel + code:IXSOTTVG + +cartridge sha256:758ea7bee928136abf612ba564fab4dd4f3caa951cb685bc8e1d4533c7b0680e + title:Formula One - Built to Win (USA) + cheat + description:Infinite nitro + code:SXUIXEVK + cheat + description:Better nitro + code:ATKSXAAZ + cheat + description:Psycho speed + code:AAVSOAZA + cheat + description:Items cost nothing + code:ATNUVUSZ + cheat + description:Items for free + code:ATNUVUSZ+ATVUKLST + +cartridge sha256:e9fe69c87a9ab1183ce8492843bacf868e1f8df2fd4e1441403091d13025a619 + title:Fox's Peter Pan & the Pirates - The Revenge of Captain Hook (USA) + cheat + description:Infinite lives + code:SZOKYLVG + cheat + description:Infinite flight meter + code:SZVSXXVK + cheat + description:Slower flight meter + code:GASSNZGE + cheat + description:Faster flight meter + code:ZASSNZGA + cheat + description:Faster flying left and right + code:ZAUIUZPA+ZAOIVAPA + cheat + description:Start with 30 units of health + code:TONGZKZE+TPXKYUZE + cheat + description:Start with 5 units of health + code:IENGZKZA+IAXKYUZA + cheat + description:Start with 1 life + code:PENKLGLA + cheat + description:Start with 6 lives + code:TENKLGLA + cheat + description:Start with 9 lives + code:PENKLGLE + cheat + description:Infinite health + code:0051:FF + cheat + description:Infinite lives (alt) + code:0050:09 + cheat + description:Infinite Flight meter (alt) + code:0640:FF + +cartridge sha256:682a0629d25275a95975e3822ded9fc6cfe5ce8dfb4650aeda0981bfe6a6afc0 + title:Frankenstein - The Monster Returns (USA) + cheat + description:Invincibility + code:ZEVKLGAA + cheat + description:Invincible after you die once (may get stuck in boss stages) + code:SZKEPASA+SZEGPASA + cheat + description:Infinite health + code:SXKELLSA+SZNOYASA+SXKEOLSA+SXUOZASA+SXUOGASA + cheat + description:Can't collect extra energy + code:SZEEULSA + cheat + description:Die after one hit + code:EEKAYLEL + cheat + description:Start with 0 continue + code:PEOGYPLA + cheat + description:Infinite health (alt) + code:007D:08 + +cartridge sha256:995b57f7d2c68a5689549fc53645dcc44f871c8d172e15deafd7389bc3f6ee0a + title:Freedom Force (USA) + cheat + description:Infinite health + code:GZVAYLSA + cheat + description:Infinite ammo + code:AEUTLYZZ + cheat + description:Infinite errors allowed + code:OXOTYNOK + cheat + description:Fewer errors allowed + code:LEOVAYTA + cheat + description:Start with half health + code:GAKVYVAO + cheat + description:Start with half ammo + code:ZOOTYTGZ + cheat + description:Start at level 2 + code:ZAUTLTPA + cheat + description:Start at level 3 + code:LAUTLTPA + cheat + description:Start at level 4 + code:GAUTLTPA + cheat + description:Start at level 5 + code:IAUTLTPA + cheat + description:Infinite health - P1 + code:0516:18 + cheat + description:Infinite health - P2 + code:0526:18 + cheat + description:Infinite ammo - P1 + code:0515:24 + cheat + description:Infinite ammo - P2 + code:0525:24 + cheat + description:Infinite errors allowed - P1 + code:0517:00 + cheat + description:Infinite errors allowed - P2 + code:0527:00 + cheat + description:Infinite time in bonus stages (disable to continue) + code:0089:09 + cheat + description:Automatically finish stage + code:00C2:3C + +cartridge sha256:ea054316b0e2ab99c2dcbcccacb4f28bae6809f183d29a4cb797a07f55ad8ff8 + title:Free Fall (USA) (Proto) + cheat + description:Infinite hands + code:OLNKSVOO + cheat + description:Freeze time (disable at end of level so counter can decrease) + code:SLKIAASP + cheat + description:One saved to beat level + code:OZVSZGSX+IYVSIKEI+PAVSTGGA + cheat + description:No score decrease with loss of men + code:AAOGUTZV+ALOGXTSZ + cheat + description:Each dead man, one to score instead of five + code:LTOGUTZT + +cartridge sha256:7e94b4fe8c33439779bb653d007ba4678dd589636ffbc87d1535629578a64d5e + title:Friday the 13th (USA) + cheat + description:Invincibility + code:SZEXSYAX + cheat + description:Infinite health + code:SZESKSSE + cheat + description:Infinite health for active counselor + code:OTEIVISV + cheat + description:Infinite child save time + code:SZNUGYAX + cheat + description:Infinite children + code:SZSLUEVK+IYKLSEAY + cheat + description:Hit anywhere + code:AIKIUGEI + cheat + description:One hit kills + code:AEOSOGZP + cheat + description:Enemies die automatically + code:AESGXZZZ + cheat + description:No enemies + code:AEKGKLZA+SXXISXVN + cheat + description:Vitamins heal active counselor better + code:ZZOUAGTE + cheat + description:Vitamins heal others better + code:AZEVXLGE + cheat + description:Autofire + code:INNLIZGY + cheat + description:Everyone can jump high + code:GAEUZIAE + cheat + description:Turbo running + code:SZVLGXOU+YPVLIXAV + cheat + description:Throw rocks straight + code:YEEGIZSZ + cheat + description:Start with 55 children + code:IEVANTPA+YUNESVYA + cheat + description:Invincibility (alt) + code:0488:03 + cheat + description:Infinite health (alt) + code:0505:FF + cheat + description:Infinite Medicine + code:0519:09 + cheat + description:Infinite Children + code:0504:05 + cheat + description:Infinite child save time (alt) + code:058D:09 + cheat + description:Have the Torch + code:0506:00 + cheat + description:Have the Knife + code:0506:01 + cheat + description:Have the Axe + code:0506:02 + cheat + description:Have the Stone + code:0506:03 + cheat + description:Have the Cleaver + code:0506:04 + cheat + description:Have the Pitchfork + code:0506:05 + cheat + description:Have the Lighter Torch + code:0517:01 + cheat + description:Have the Flashlight + code:0518:01 + cheat + description:Have the Key + code:051A:01 + cheat + description:Jason has no health + code:051C:00 + cheat + description:Play as George + code:0507:00 + cheat + description:Play as Mark + code:0507:01 + cheat + description:Play as Paul + code:0507:02 + cheat + description:Play as Laura + code:0507:03 + cheat + description:Play as Debbie + code:0507:04 + cheat + description:Play as Crissy + code:0507:05 + cheat + description:Set time - day + code:0508:00 + cheat + description:Set time - dusk + code:0508:01 + cheat + description:Set time - night + code:0508:02 + +cartridge sha256:d077b282b751a246549e334885d83ee587d9e6178b170afcf57553ec62015c52 + title:G.I. Joe - A Real American Hero (USA) + cheat + description:Invincibility + code:ESVOGGEY+XVNPAKAU + cheat + description:Infinite health + code:OLNTYKOO + cheat + description:Infinite ammo + code:SXVXOVSE + cheat + description:Infinte time + code:SXNETUSE + cheat + description:Infinite time (alt) + code:AENATLPA + cheat + description:More health - Duke + code:GOUTKSIA + cheat + description:More health - Blizzard + code:GOUTSSGA + cheat + description:More health - Snake Eyes + code:GOUTVSZA + cheat + description:More health - Capt. Grid-Iron + code:GOUTNSLA + cheat + description:More health - Rock and Roll + code:GOUVESPA + cheat + description:Less health - Duke + code:TEUTKSIA + cheat + description:Less health - Blizzard + code:TEUTSSGA + cheat + description:Less health - Snake Eyes + code:IEUTVSZA + cheat + description:Less health - Capt. Grid-Iron + code:IEUTNSLA + cheat + description:Less health - Rock and Roll + code:GEUVESPA + cheat + description:Shorter immunity + code:ALNVIKAY + cheat + description:Longer immunity + code:NYNVIKAN + cheat + description:Max health on pick-up + code:AAUEPPLA + cheat + description:Mega-jump - Duke + code:AXNVKIYP + cheat + description:Mega-jump - Blizzard + code:AXNVSIZP + cheat + description:Mega-jump - Snake Eyes + code:AXNVVSGP + cheat + description:Mega-jump - Capt. Grid-Iron + code:AXNVNIGP + cheat + description:Mega-jump - Rock and Roll + code:AZETETAP + +cartridge sha256:9e65e4d55123612c5eb05b332e48fd975a187d706a3fd44b62125e1ae48af028 + title:G.I. Joe - The Atlantis Factor (USA) + cheat + description:Invincibility + code:EISPUZEY+XTSPNXAU + cheat + description:Infinite health + code:OUSTLSOO + cheat + description:Infinite time + code:AASEZIPA + cheat + description:Infinite Mines + code:SUOPEUVS + cheat + description:Infinite stamina + code:SXSTLSOP+SUOAISSO + cheat + description:Infinite bullets after obtaining a power up shell + code:GXSUZVSE+GXVLTVSE + cheat + description:Don't flash after getting hit + code:AESVPSAY + cheat + description:Flash about half as long after getting hit + code:PUSVPSAN + cheat + description:Each Pow worth increases player level by one + code:GAXPPYPA + cheat + description:Infinite ammo + code:SXSUZVSE+SXVLTVSE+SXSLIVVK+SXVUPVSE + cheat + description:Start with all characters + code:YUKETLPE + cheat + description:Start with 500 bullets + code:IAEELGPA + cheat + description:Start with 1 life + code:PENVSYIA + +cartridge sha256:023ff157d96a8efc847c7d7cbe89574091fe099996e6283c63e3fb58918f3502 + title:Gaiapolis (Asia) (Unl) + cheat + description:Invincibility + code:EIKANTEY + cheat + description:Infinite time + code:SZUKVPVG + cheat + description:Infinite credits + code:SXXGSVVK + +cartridge sha256:a636a947acf1ef0b50e66d31699b64aa4f3b4865e2f2031385780974fb6d8c91 + title:Galactic Crusader (USA) (Unl) + cheat + description:Invincibility + code:EIUNTPEY + cheat + description:Infinite lives + code:VXUSUTVG + +cartridge sha256:df49cc788fff36881fcf1d1cb22281d305260d4d8fbbe07ca2c4d699fe54843a + title:Galaga - Demons of Death (USA) + cheat + description:Invincibility + code:ATNVSAVZ + cheat + description:Infinite lives + code:XVOKVUXK + cheat + description:Play challenge stages only + code:GXOKOTEI + cheat + description:Can't be caught by tractor beam + code:OXSTZPSX+YESTLOPY + cheat + description:Press Start for next wave + code:KPNIPZEA+GANIZZIA+AAVSIZPA + cheat + description:Press Start for extra life + code:GGVSGXOX+EZVSIZPE+UGVSTZSE + cheat + description:Start with twin shots + code:GXEVPAEI + cheat + description:Start with 1 life + code:PAKKKILA + cheat + description:Start with 6 lives + code:TAKKKILA + cheat + description:Infinite lives (alt) + code:0485:05+0487:05 + +cartridge sha256:e6fe68b9f12578e74ba016ca146aaf8232b20475fb675c7d32e0ea4e47eb1cc8 + title:Galaga (Japan) + cheat + description:Invincibility + code:ATETKOOZ + cheat + description:Infinite lives + code:XVOKVUXK + cheat + description:Keep double ship after being destroyed + code:AVNTKEOZ + cheat + description:Only one part to collect + code:PESEGPGT + cheat + description:Always get a perfect bonus + code:PXVIIEOK+AEVITEAZ + cheat + description:Start with double shot + code:SSVGILEA+PZKGNISO + cheat + description:Infinite lives (alt) + code:0485:05+0487:05 + +cartridge sha256:50178a2856f8ed3574b4e7fd45b9d1ec44c660d51fe9783d0012a19df5892cce + title:Galaxian (Japan) + cheat + description:Infinite lives + code:0042:05 + +cartridge sha256:c019750cc439810de6cbf1c3a895099674df3f397744ad3149ba1b25dd55d0ab + title:Galaxy 5000 (USA) + cheat + description:Infinite time + code:SLKPAEVS + cheat + description:Reduce damage free of charge + code:GXNXSVSN + cheat + description:No damage from falling + code:SXKZEPAX + cheat + description:Take less damage + code:OXNNVPSX+PENNNOZP + cheat + description:More damage from falling + code:SXUXSOSU+ALVUVYLZ + cheat + description:More damage from shots + code:TEEOZGVV+NUEOLKVN + cheat + description:Always in 1st place - P1 + code:00AB:00 + cheat + description:Always in 1st place - P2 + code:00AC:00 + cheat + description:Always in 1st place - P3 + code:00AD:00 + cheat + description:Always in 1st place - P4 + code:00AE:00 + cheat + description:Infinite time (one's digit) + code:069A:09 + cheat + description:Infinite time (ten's digit) + code:069B:09 + cheat + description:Infinite time (hundred's digit) + code:069C:09 + +cartridge sha256:055fb73baaed0f3c4a31902402e7fe581d2d2cb948d3a2f5c3552050f316e6df + title:Gargoyle's Quest II (USA) + cheat + description:Invincibility (except Doppelganger when it mimics you) + code:OESAKAIE + cheat + description:Invincible against spikes + code:KVNVYLIA + cheat + description:Infinite fight + code:OXSELPSX + +cartridge sha256:fbc976422ca910d9391060898c8b58694f19b6e53a68bd33c457fb38dac1e5c6 + title:Gauntlet (USA) (Unl) + cheat + description:Infinite health + code:SLNAEYSP+SLVPOASP + cheat + description:Infinite keys + code:PAOXVLAE+SAXZOLSZ + cheat + description:Infinite time in puzzle and treasure rooms + code:XVOONAVK + cheat + description:Infinite time in puzzle and treasure rooms (alt) + code:00C0:1E + cheat + description:Have all power-ups - P1 + code:00AC:3F + cheat + description:Have all power-ups - P2 + code:00AD:3F + cheat + description:Have Invisibility - P1 + code:00AA:01 + cheat + description:Have Invisibility - P2 + code:00AC:01 + cheat + description:Have Invulnerability - P1 + code:00AA:20 + cheat + description:Have Invulnerability - P2 + code:00AC:20 + cheat + description:Have Reflective shot - P1 + code:00AA:04 + cheat + description:Have Reflective Shot - P2 + code:00AC:04 + cheat + description:Have Repulsiveness - P1 + code:00AA:02 + cheat + description:Have Repulsiveness - P2 + code:00AC:02 + cheat + description:Have Super Shot - P1 + code:00AA:10 + cheat + description:Have Super Shot - P2 + code:00AC:10 + +cartridge sha256:fd2a8520314fb183e15fd62f48df97f92eb9c81140da4e6ab9ff0386e4797071 + title:Gauntlet (USA) + cheat + description:Infinite health + code:SLNAEYSP+SLVPOASP + cheat + description:Infinite keys + code:PAOXVLAE+SAXZOLSZ + cheat + description:Infinite time in puzzle and treasure rooms + code:XVOONAVK + cheat + description:Infinite time in puzzle and treasure rooms (alt) + code:00C0:1E + cheat + description:Have all power-ups - P1 + code:00AC:3F + cheat + description:Have all power-ups - P2 + code:00AD:3F + cheat + description:Have Invisibility - P1 + code:00AA:01 + cheat + description:Have Invisibility - P2 + code:00AC:01 + cheat + description:Have Invulnerability - P1 + code:00AA:20 + cheat + description:Have Invulnerability - P2 + code:00AC:20 + cheat + description:Have Reflective shot - P1 + code:00AA:04 + cheat + description:Have Reflective Shot - P2 + code:00AC:04 + cheat + description:Have Repulsiveness - P1 + code:00AA:02 + cheat + description:Have Repulsiveness - P2 + code:00AC:02 + cheat + description:Have Super Shot - P1 + code:00AA:10 + cheat + description:Have Super Shot - P2 + code:00AC:10 + +cartridge sha256:ffa61d9f7bfb1d60662ddf246b21a8756d518292e8fdc0f58ac1c9b3fbad672d + title:Gauntlet II (USA) + cheat + description:Infinite health + code:SLXSNNSO+SLETYXSO + cheat + description:Take less damage + code:OTXSSYSV+ZAXSVYAA + cheat + description:Infinite keys (new game) + code:PAOVYAAA+SZVTEUVS + cheat + description:Infinite time in treasure rooms + code:XVOTGXSU + cheat + description:Walk through walls + code:APUVTIEP+ELSVGIEP + cheat + description:Weaker poison + code:ZLVVVIGT + cheat + description:Stronger poison + code:EGVVVIGV + cheat + description:5 super shots on pick-up + code:IAUTEUZA + cheat + description:20 super shots on pick-up + code:GPUTEUZA + cheat + description:Invincibility lasts longer + code:AYETVUGU + cheat + description:Invincibility doesn't last as long + code:LPETVUGU + cheat + description:Repulsiveness lasts longer + code:ANNTUXGU + cheat + description:Repulsiveness doesn't last as long + code:LONTUXGU + cheat + description:Invisibility lasts longer + code:AYOTKUGU + cheat + description:Invisibility doesn't last as long + code:LPOTKUGU + cheat + description:Infinite health - P1 + code:0739:FF + cheat + description:Infinite health - P2 + code:073A:FF + cheat + description:Infinite health - P3 + code:073B:FF + cheat + description:Infinite health - P4 + code:073C:FF + cheat + description:Infinite Keys - P1 + code:0743:04 + cheat + description:Infinite Keys - P2 + code:0744:04 + cheat + description:Infinite Keys - P3 + code:0745:04 + cheat + description:Infinite Keys - P4 + code:0746:09 + cheat + description:Infinite Potions - P1 + code:0748:03 + cheat + description:Infinite Potions - P2 + code:0749:03 + cheat + description:Infinite Potions - P3 + code:074A:03 + cheat + description:Infinite Potions - P4 + code:074B:03 + cheat + description:Have Invulnerability - P1 + code:0707:FF + cheat + description:Have Invulnerability - P2 + code:0708:FF + cheat + description:Have Invulnerability - P3 + code:0709:FF + cheat + description:Have Invulnerability - P4 + code:070A:FF + cheat + description:Have Reflective Shot - P1 + code:0716:FF + cheat + description:Have Reflective Shot - P2 + code:0717:FF + cheat + description:Have Reflective Shot - P3 + code:0718:FF + cheat + description:Have Reflective Shot - P4 + code:0719:FF + cheat + description:Have Repulsiveness - P1 + code:0711:FF + cheat + description:Have Repulsiveness - P2 + code:0712:FF + cheat + description:Have Repulsiveness - P3 + code:0713:FF + cheat + description:Have Repulsiveness - P4 + code:0714:FF + cheat + description:Have Super Shot - P1 + code:071B:0A + cheat + description:Have Super Shot - P2 + code:071C:0A + cheat + description:Have Super Shot - P3 + code:071D:0A + cheat + description:Have Super Shot - P4 + code:071E:0A + cheat + description:Have Transportability - P1 + code:0720:FF + cheat + description:Have Transportability - P2 + code:0721:FF + cheat + description:Have Transportability - P3 + code:0722:FF + cheat + description:Have Transportability - P4 + code:0723:FF + +cartridge sha256:cf517940496d6085563bdbbe74f4a06d2c4eca48da8eb2b35d5cfe463df35ce4 + title:George Foreman's KO Boxing (USA) + cheat + description:Infinite health + code:036E:43 + cheat + description:Knock opponent down with 1 punch + code:036F:01 + +cartridge sha256:43221ae8a386e8ddf68251d5870d6fe3d696be14a5e41d9a44c36227894044d8 + title:Ghostbusters (USA) + cheat + description:Infinite fuel + code:SXKZAZVG + cheat + description:Infinite energy during Gozer fight + code:SZVYAUSE + cheat + description:Immune to ghosts on Zuul stairway + code:OXOXKPVK + cheat + description:Permanent ghost alarm + code:PAEEXKPX + cheat + description:Permanent ghost vacuum + code:PASPLOPX + cheat + description:Self-emptying traps + code:OXSESGSX + cheat + description:Super sprinting up Zuul stairway + code:AEEZOAPA + cheat + description:Stay Puft does not climb building during Gozer fight + code:SZXYVOVV + cheat + description:Gozer dies in one hit + code:EIUYZLEY + cheat + description:No walk up Zuul stairway + code:AAXXPTYP + cheat + description:Start with $1,000,000 + code:AVVETNTI + +cartridge sha256:1ea36ebd81692d3a3c1db217e0df832f060c1566c69a74fac299aaeb0d8eb82f + title:Ghostbusters II (USA) + cheat + description:Invincibility + code:EINPOYEY+ESVOKIEY + cheat + description:Infinite lives + code:SUKYAUVS + cheat + description:Infinite continues + code:SZXPSXVK + cheat + description:Triple continues + code:TAEGTAZA + cheat + description:Rapid-firing proton rifle + code:ZEEOOXYO + cheat + description:All Ghostbusters can mega-jump + code:KYSOKXVN + cheat + description:Shield lasts longer - car scenes + code:NNXXAPAS + cheat + description:Infinite shield - car scenes + code:SZOXLNVK + cheat + description:Start with 1 life + code:AAXVGGLA + cheat + description:Start with 6 lives + code:IAXVGGLA + cheat + description:Start with 9 lives + code:AAXVGGLE + +cartridge sha256:eea66f7bcc90d1145454da487791be5926473bee4014313af12dfa0f7453ea81 + title:Ghosts'n Goblins (USA) + cheat + description:Invincibility + code:AEVNGIPA + cheat + description:Infinite armor + code:SKITTL + cheat + description:Infinite lives - both players + code:SZEGNOVK + cheat + description:Infinite time + code:SXOITUVK + cheat + description:Hit anywhere + code:ALEYYTEO+ATENATPA+OUKYPSOO+OUUUTVOO + cheat + description:Enable stage select (disable after loading stage) + code:AAVIZEYA + cheat + description:Speed up game + code:ZAKILZLA + cheat + description:Slow down game + code:GAKILZLA + cheat + description:Start with Axe + code:TUNKYIAG + cheat + description:Start with Dagger + code:ZKNKYIAG + cheat + description:Start with Fireball + code:GKNKYIAG + cheat + description:Start with Cross + code:YKNKYIAK + cheat + description:Start with Blue Sphere + code:KXNKYIAK + cheat + description:Start with 1 life - both players + code:PAEKPTLA + cheat + description:Start with 6 lives - both players + code:TAEKPTLA + cheat + description:Start with 9 lives - both players + code:PAEKPTLE + cheat + description:Start with 4 lives - P1 + code:VAEKZVSE + cheat + description:Enable stage select (disable after loading stage) + code:00A7:0F + cheat + description:Automatically complete level + code:00BF:01: + cheat + description:Game difficulty - normal + code:00AA:00 + cheat + description:Game difficulty - hard + code:00AA:01 + cheat + description:Game difficulty - harder + code:00AA:02 + cheat + description:Game difficulty - hardest + code:00AA:03 + cheat + description:Game difficulty - expert + code:00AA:04 + +cartridge sha256:48aaef58dee3ad370546db569306e40aeecd27b88b7faef3ccd9b8b818c9ea71 + title:Ghoul School (USA) + cheat + description:Invincibility + code:SZKZOZAX + cheat + description:Infinite health + code:SXSXSUSE + cheat + description:Infinite lives + code:SXEKYVVK + cheat + description:Infinite health (alt) + code:060A:FF + cheat + description:Infinitel lives (alt) + code:0467:09 + cheat + description:One hit kills on most enemies + code:060D:00+060E:00+060F:00+0610:00+0611:00+0612:00+0613:00 + +cartridge sha256:bf22e6aff97bb44210987f5631c1667d4fa75ef79522e8c46dbb3b0f4877896b + title:Goal! (USA) + cheat + description:CPU score adds to your score + code:OGOKLYEN+OGOKYYEN + +cartridge sha256:7911375ab98da4ac5c628ba4dfffcba8ba4fc13a341901aed120ab967be5e26c + title:Goal! Two (USA) + cheat + description:Infinite time - Italy, P2 + code:SZEYAPVG + cheat + description:P2 or computer can't score - Italy, P2 + code:SXNELNSE + cheat + description:Start with more KP - Italy, P2 + code:AZKIANPA + cheat + description:Start with a lot of KP - Italy, P2 + code:AIKIANPA + cheat + description:Start with mega KP - Italy, P2 + code:OPKIANPE + cheat + description:Start with more TP - Italy, P2 + code:AZKIPYYA + cheat + description:Start with a lot of TP - Italy, P2 + code:AIKIPYYA + cheat + description:Start with mega TP - Italy, P2 + code:OPKIPYYE + +cartridge sha256:c2383e5cd8670c7107d59887026b9001f30045aa5f07be4b687b7a6bc290db1f + title:Godzilla - Monster of Monsters! (USA) + cheat + description:Infinite life (health) + code:018C:30 + cheat + description:Infinite power + code:0178:30 + +cartridge sha256:af24262bc78865b81b1a42d2842e222553fca27fb841a4eb8fbe26da7eba6163 + title:Golf Grand Slam (USA) + cheat + description:Strokes aren't recorded + code:SXEZGYSA + cheat + description:Some shots can be done more accurately + code:PEXTETIA + cheat + description:Wind always at 9 + code:OZOIPGIX+PAOIZKAX+SXSZZYSA + +cartridge sha256:9f559f83b9b5179137069bae0ca4b8eacf84378892b598044b88ef50681b58bb + title:Golgo 13 - Top Secret Episode (USA) + cheat + description:Infinite health + code:SZOETGSA+OXKVXAVK+SXKNNPSA + cheat + description:Health does not gradually decrease + code:SXKVXAVG + cheat + description:Infinite bullets in horizontal mode + code:GXUVXTSA + cheat + description:Infinite damage in horizontal mode + code:GXKNNPSA + cheat + description:Infinite damage in pan/zoom mode + code:GZOEGGST + cheat + description:Infinite damage in maze + code:GZKLZGST + cheat + description:Have a health and bullets boost + code:ZAVKIAAA + +cartridge sha256:16c7de15b7dc72c567f58172bbf0cd1328d11625f6707814da030df15f95dc92 + title:Goonies II, The (USA) + cheat + description:Invincibility + code:SESEZESX + cheat + description:Infinite health + code:SZSUNTSA + cheat + description:Infinite time + code:SSOOUZVI + cheat + description:Infinite lives + code:SZUGUYVG + cheat + description:Infinite Bombs on pick-up + code:SXUASSVK + cheat + description:Infinite Molotov Bombs on pick-up + code:SZVAESVK + cheat + description:Infinite Sling Shots on pick-up + code:SZNEEVVK + cheat + description:Super-jump + code:YEUAOPZA + cheat + description:Mega-jump + code:LEUAOPZA + cheat + description:Better Jumping Boots on pick-up + code:IEUEKPGA + cheat + description:Super-speed + code:ZESAPAPA + cheat + description:Walk through walls + code:AOSAYVOG+APSAZYEY+SZNAANSE + cheat + description:Start with all items + code:YPVIAGPE + cheat + description:Start with Boomerang + code:IAVIAGPA + cheat + description:Start with 4 health cells + code:GAUIZGZA+AGUIYGAZ + cheat + description:Start with 8 health cells + code:AAUIZGZE+EAUIYGAZ + cheat + description:Start with 1 life + code:PAXSZGLA + cheat + description:Start with 6 lives + code:TAXSZGLA + cheat + description:Start with 9 lives + code:PAXSZGLE + cheat + description:Invincibility (alt) + code:0516:41 + cheat + description:Infinite health (alt) + code:0503:20 + cheat + description:Infinite lives (alt) + code:0022:09 + cheat + description:Have all weapons + code:050B:FF+050C:FF + cheat + description:Have all Implements + code:050A:FF + cheat + description:Infinite Keys + code:0500:08 + +cartridge sha256:15685dee8bc1c588dfa2649b7b5f715aa7b4136454ba09c046d1b17209749d76 + title:Gotcha! - The Sport! (USA) + cheat + description:Infinite time + code:AASUTIPA + cheat + description:Increase timer to 59 seconds + code:IAEPOAGA+PAEPVAIE + cheat + description:Decrease timer to 25 seconds + code:ZAEPOAGA+IAEPVAIA + cheat + description:Start with double rations of ammo + code:ZAEOKAPA + cheat + description:Enemies never shoot at you + code:05F1:63 + cheat + description:Infinite ammo + code:061A:09+061B:09 + cheat + description:Infinite time (alt) + code:061E:09+061F:09 + +cartridge sha256:6918d7cbb81bfcd20d95bb08bcf137c7ea80ae9f0c12b92bfdcc90a6cf9752a0 + title:Gradius (USA) + cheat + description:Infinite lives - both players + code:SXOOYYVI + cheat + description:Keep power capsules + code:KOXOLYSP + cheat + description:Increase force field protection + code:NNOEKPIE + cheat + description:Never lose weapons + code:YGUONUZS+YGKPUUIL + cheat + description:Hit anywhere + code:AAOKYAAP+AAXKGALA + cheat + description:Start with 1 life - both players + code:AENELZLA + cheat + description:Start with 6 lives - both players + code:IENELZLA + cheat + description:Start with 9 lives - both players + code:AENELZLE + +cartridge sha256:2974ad16b994cfdc9418310ced6c7f4ed64433063d12439a7b37a816f797dd0e + title:Gradius II (Japan) + cheat + description:Invincibility + code:ATENGIAZ + +cartridge sha256:fe3d2f94dadd3b2437e45ed9a38276b8b32af9e25d484de79c3cc7bf60eef386 + title:Grand Master (Japan) + cheat + description:Invincibility + code:0420:01 + cheat + description:Infinite HP + code:044F:20 + cheat + description:Infinite MP + code:0450:20 + cheat + description:Have Armor + code:0439:01 + cheat + description:Have Axe + code:0431:01 + cheat + description:Have Boots + code:0435:01 + cheat + description:Have Cross + code:043B:01 + cheat + description:Have Diamond + code:0437:01 + cheat + description:Have Exit Key + code:0436:01 + cheat + description:Have Harp + code:0434:01 + cheat + description:Have Hourglass + code:043C:01 + cheat + description:Have Mirror + code:043E:01 + cheat + description:Have Morning Star + code:0433:01 + cheat + description:Have Necklace + code:043D:01 + cheat + description:Have Potion + code:0438:01 + cheat + description:Have Red Sword + code:0430:01 + cheat + description:Have Rod + code:0432:01 + cheat + description:Have Shield + code:043A:01 + +cartridge sha256:60a7d102deac7491e08b7ed5a7b96e66e09758b8411f682a4df1a7e8b49e55c5 + title:Great Waldo Search, The (USA) + cheat + description:Only need to find Waldo to complete the level + code:EKEIXTEA + cheat + description:Only need to find the magic scroll + code:EKXSNTAG + cheat + description:Faster timer + code:ZEKKOTPA + cheat + description:Much faster timer + code:GEKKOTPA + cheat + description:Play the Super Waldo Challenge + code:OZSIEEOV+GASIOALA + cheat + description:Extra clocks last forever + code:SXSGKTVG + cheat + description:Extra clocks worth nothing + code:SZXINYVT + +cartridge sha256:2b77da430b08e6a91a3453fde8ea82692415d44c3e953fdf281aa39352d5289d + title:Gremlins 2 - The New Batch (USA) + cheat + description:Invincibility + code:EYESUIEI + cheat + description:Infinite health + code:SXKEZPVG + cheat + description:Infinite lives + code:SZNETEVK + cheat + description:Infinite balloons + code:SZXEUXVK + cheat + description:Start with 5 lives + code:GAEGEAAA + cheat + description:Start with 10 lives + code:PAEGEAAE + cheat + description:Start with 3 balloons + code:LAEGSAPA + cheat + description:Start with 6 balloons + code:TAEGSAPA + cheat + description:Start with only 1 heart + code:ZAEKXATA+ZEEELATA + cheat + description:Start with 4 hearts + code:AAEKXATE+AEEELATE + cheat + description:Invincibility after one hit + code:00A9:09 + cheat + description:Infinite health (alt) + code:00AD:06 + cheat + description:Infinite lives (alt) + code:057C:03 + cheat + description:Infinite Balloons (alt) + code:050C:05 + cheat + description:Infinite Crystals + code:056C:FF + cheat + description:One hit kills on bosses + code:0360:00 + +cartridge sha256:d18ad8b76f9d067858dc8012ee84119c90524cdc3f4d555dd5a752a6f469fe6b + title:Guardian Legend, The (USA) + cheat + description:Invincibility + code:AVKSLZSZ + cheat + description:Infinite health + code:AAXTIUNY + cheat + description:Hit anywhere + code:AASIYUYT+EGSITLIZ+EISSALEY+PASSPLIE + cheat + description:Use up minimum shots + code:OVOAKLSV+PEOASLAP + cheat + description:Never use up shots (To finish the game, save before opening the entrance to corridor 6. Restart with no codes and go through the enterance. Save again, then restart.) + code:GXOAKLST + cheat + description:Start with less health + code:AXVAIAAG + cheat + description:Start with more health + code:EEVAIAAG + cheat + description:Start on area 1 + code:PAKVELAA + cheat + description:Start on area 3 + code:LAKVELAA + cheat + description:Start on area 5 + code:IAKVELAA + cheat + description:Start on area 7 + code:YAKVELAA + cheat + description:Start on area 9 + code:PAKVELAE + cheat + description:Fighter shape (Adventure and Space mode) + code:0030:50 + cheat + description:Fighter shape in TGL mode (Adventure and Space mode) + code:0030:52 + cheat + description:Max consecutive firing + code:003A:01 + cheat + description:Have 2-way shot + code:003A:01 + cheat + description:Have 3-way shot + code:003A:02 + cheat + description:Have 4-way shot + code:003A:03 + cheat + description:Max weapon power - Blue + code:003D:01 + cheat + description:Max weapon power - Green + code:003D:02 + cheat + description:Max weapon power - Red + code:003D:03 + cheat + description:Start on area 10 + code:0050:0A + cheat + description:Start on Corridor 01 + code:0051:01 + cheat + description:Start on Corridor 02 + code:0051:02 + cheat + description:Start on Corridor 03 + code:0051:03 + cheat + description:Start on Corridor 04 + code:0051:04 + cheat + description:Start on Corridor 05 + code:0051:05 + cheat + description:Start on Corridor 06 + code:0051:06 + cheat + description:Start on Corridor 07 + code:0051:07 + cheat + description:Start on Corridor 08 + code:0051:08 + cheat + description:Start on Corridor 09 + code:0051:09 + cheat + description:Start on Corridor 10 + code:0051:0A + cheat + description:Start on Corridor 11 + code:0051:0B + cheat + description:Start on Corridor 12 + code:0051:0C + cheat + description:Start on Corridor 13 + code:0051:0D + cheat + description:Start on Corridor 14 + code:0051:0E + cheat + description:Start on Corridor 15 + code:0051:0F + cheat + description:Start on Corridor 16 + code:0051:10 + cheat + description:Start on Corridor 17 + code:0051:11 + cheat + description:Start on Corridor 18 + code:0051:12 + cheat + description:Start on Corridor 19 + code:0051:13 + cheat + description:Start on Corridor 20 + code:0051:14 + cheat + description:Start on Corridor 21 + code:0051:15 + cheat + description:Start on Corridor 22 + code:0051:16 + +cartridge sha256:a2033c3b3d9f54b37fad8083604d37e2b2cb4ff77e0e183021141f55dfa9c4cd + title:Guerrilla War (USA) + cheat + description:Invincibility + code:EYSTGGEI+EIETUGEY + cheat + description:Infinite lives - both players + code:SLTKOV + cheat + description:Infinite lives - both players (alt) + code:SZVKOVVS + cheat + description:Keep weapon after death + code:SXUTEUSO + cheat + description:Press Start to complete the level + code:LASKYYPO + cheat + description:Start a new game to view the ending + code:PEXXAEAE + cheat + description:Start with 1 life - both players + code:AELGVP + cheat + description:Start with 6 lives - both players + code:IELGVP + cheat + description:Start with 9 lives - both players + code:PELGVO + cheat + description:Invincibility - P1 + code:0680:02 + cheat + description:Invincibility - P2 + code:0681:02 + cheat + description:Infinite lives - P1 + code:0028:05 + cheat + description:Infinite lives - P2 + code:0029:04 + cheat + description:Infinite time for tank + code:04C2:FA + cheat + description:Start on stage 2 (disable after loading stage) + code:0039:01 + cheat + description:Start on stage 3 (disable after loading stage) + code:0039:02 + cheat + description:Start on stage 4 (disable after loading stage) + code:0039:03 + cheat + description:Start on stage 5 (disable after loading stage) + code:0039:04 + cheat + description:Start on stage 6 (disable after loading stage) + code:0039:05 + cheat + description:Start on stage 7 (disable after loading stage) + code:0039:06 + cheat + description:Start on stage 8 (disable after loading stage) + code:0039:07 + cheat + description:Start on stage 9 (disable after loading stage) + code:0039:08 + cheat + description:Start on stage 10 (disable after loading stage) + code:0039:09 + +cartridge sha256:4628f32db9b826d19fe5dd8e2c45a9f70e1041f15b7b44b06dee2f01731566e8 + title:Gumshoe (USA, Europe) + cheat + description:Gain 1 bullet on pick-up + code:PASAUALA + cheat + description:Gain 6 bullets on pick-up + code:TASAUALA + cheat + description:Timer set to 04:00 + code:LAKEGYTA + cheat + description:Timer set to 10:00 + code:PAKEGYTE + cheat + description:Different attack waves + code:SAKAVEKE + cheat + description:Start with 1 life + code:PAUENALA + cheat + description:Start with 6 lives + code:TAUENALA + cheat + description:Start with 9 lives + code:PAUENALE + cheat + description:Start with 25 bullets + code:IZSEEAAI + cheat + description:Start with 150 bullets + code:PASEKAAA + cheat + description:Start with 250 bullets + code:ZASEKAAA + +cartridge sha256:d22a0c390dfc47c99226226c98158bf0ca3b4cd07dbd3d46cc50c2f1b9303c22 + title:Gun Nac (USA) + cheat + description:Invincibility + code:AGEZPAAI+AGUXGPAI + cheat + description:Infinite lives + code:SXOZYUSE + cheat + description:Infinite special weapons + code:SXVZTXSE + cheat + description:Invincibility (alt) + code:0400:02 + cheat + description:Infinite lives (alt) + code:018D:03 + cheat + description:Infinite Bombs + code:018F:04 + cheat + description:Weapon level 1 + code:0033:00 + cheat + description:Weapon level 2 + code:0033:01 + cheat + description:Weapon level 3 + code:0033:02 + cheat + description:Weapon level 4 + code:0033:03 + cheat + description:Weapon level 5 + code:0033:04 + cheat + description:Weapon level 6 + code:0033:05 + cheat + description:Weapon level 7 + code:0033:06 + cheat + description:Weapon level 8 + code:0033:07 + cheat + description:Weapon type 1 + code:0034:00 + cheat + description:Weapon type 2 + code:0034:01 + cheat + description:Weapon type 3 + code:0034:02 + cheat + description:Weapon type 4 + code:0034:03 + cheat + description:Weapon type 5 + code:0034:04 + cheat + description:Bomb power level 2 + code:003B:01 + cheat + description:Bomb power level 3 + code:003B:02 + cheat + description:Bomb power level 4 + code:003B:03 + cheat + description:Turbo power level 2 + code:003C:01 + cheat + description:Turbo power level 3 + code:003C:02 + cheat + description:Turbo power level 4 + code:003C:03 + cheat + description:Turbo power level 5 + code:003C:04 + cheat + description:Start on level 2 + code:0180:02 + cheat + description:Start on level 3 + code:0180:03 + cheat + description:Start on level 4 + code:0180:04 + cheat + description:Start on level 5 + code:0180:05 + cheat + description:Start on level 6 + code:0180:06 + cheat + description:Start on level 7 + code:0180:07 + cheat + description:Start on level 8 + code:0180:08 + +cartridge sha256:f39421a126f3b93caa37d6c3ed899840ddfd51b0587446ca459f72564aca1433 + title:Gun.Smoke (USA) + cheat + description:Infinite lives + code:SXUYTLVG + cheat + description:Keep weapons after death + code:PEXNALAA + cheat + description:Start with all weapons and lots of ammo + code:PAUTTYAA + cheat + description:Start with all weapons, lots of ammo, all 4 boots and all 4 rifle icons + code:GAUTTYAA + cheat + description:Start with 9 lives + code:PAXVTYLE + cheat + description:Start with 25 lives + code:PPXVTYLE + +cartridge sha256:0d895a031dd38f2661ba2af4a1b3c7b9753632b1530ea28eec936cf3fda8bf54 + title:Gyromite (World) + cheat + description:Invincible against enemies + code:SZUZKTAX + cheat + description:Invincible against upward crushing + code:ATOXXOOZ + cheat + description:Infinite lives + code:SUZAAI + cheat + description:Climb up through flooring + code:AESZVZLA + cheat + description:Climb down through flooring + code:AEOZEZLA + cheat + description:Slow down timer + code:ZEAAUS + cheat + description:Start with 1 life + code:PEUAGLIA + cheat + description:Start with 10 lives + code:ZEUAGLIE + cheat + description:Start with 20 lives + code:GOUAGLIA + +cartridge sha256:c6e275929764f7950ee85806ef5fdab9dda36e27f9f29935101bfc0916bf90a6 + title:Gyruss (USA) + cheat + description:Invincibility + code:OXSXTASX + cheat + description:Infinite lives + code:AEEOIEZA + cheat + description:Never lose twin shots + code:GEEPIAZA+OEEPYAPA + cheat + description:Gain 2 phasers when you die with none + code:ZEEPYAPA + cheat + description:Gain 4 phasers when you die with none + code:GEEPYAPA + cheat + description:Start with 1 ship + code:PAXEGLGA + cheat + description:Start with 10 ships + code:ZAXEGLGE + cheat + description:Start with 4 phasers + code:GAKEATPA + cheat + description:Start with 8 phasers + code:AAKEATPE + cheat + description:Start with twin shots + 1 phaser + code:OAKEATPA + cheat + description:Start with twin shots + 4 phasers + code:KAKEATPA + cheat + description:Start with twin shots + 8 phasers + code:EAKEATPE + +cartridge sha256:bd5c7925e616da879ee63ac4ac2004af26e20ae36a494247e704d41440ac971a + title:Hammerin' Harry (Europe) + cheat + description:Infinite energy (except spikes) + code:SXULUKSE + cheat + description:Infinite lives + code:SZKZKOVK + cheat + description:Invincibility + code:ESSNPTEY+SESYTVSX + +cartridge sha256:6e2b0e222eb8dba29c0ca363f1d7d59ed1fa307bafc150b5c8e1dd13638555a6 + title:Happy Pairs (Asia) (PAL) (Unl) + cheat + description:Infinite tries + code:SZKUZAVG + cheat + description:Infinite time + code:SXXUNTVG + cheat + description:Infinite autos + code:SZNLIPVG + +cartridge sha256:07bfd5bf6d3e5cea26d0a521e7d599d67a4b794c5efa66e4189877c1361aad47 + title:Harlem Globetrotters (USA) + cheat + description:Slower timer + code:IIUGSOIZ + cheat + description:Faster timer + code:GPUGSOIX + cheat + description:Slower shot clock + code:IIVGKOIZ + cheat + description:Faster shot clock + code:GPVGKOIX + +cartridge sha256:fd3c19b0339bf2b326d8a0526216b5143f035f68dabb3b3392689c92d6c140d9 + title:Heavy Barrel (USA) + cheat + description:Invincibility + code:AVVUEUPA + cheat + description:Invincibility and invisibility on second life + code:XTOVVEXK + cheat + description:Infinite lives + code:SZOTXTVG + cheat + description:Infinite Bombs + code:SXVVVLVI + cheat + description:Infinite Keys + code:SUKUZISP + cheat + description:Infinite Mace + code:OXNUTNPV + cheat + description:Infinite hand weapons on pick-up - both players + code:ENVVKLEI + cheat + description:Infinite hand weapons and firearms on pick-up - both players + code:OXVVVLVS + cheat + description:Hand weapons last 4x longer + code:AEKVXLII + cheat + description:Only 1 hand weapon + code:ZAOVEPAA + cheat + description:Autofire - P1 + code:ENSTPVSN + cheat + description:Autofire - P2 + code:EYNVINSN + cheat + description:Enemies don't fire handguns + code:XVKZVEXK + +cartridge sha256:0a23312c8e07b9af753b25c1307f07f8061d6ac4f8427f4660382d925e7a84e2 + title:Heavy Shreddin' (USA) + cheat + description:Infinite penalties + code:SXSOYIVG+SXOPPLVG+SXUOZLVG + cheat + description:Select any level + code:NNUEYLAE + cheat + description:Slow timer + code:AUEXNVAO + cheat + description:Faster left and right movement + code:ZESEKLPA+ZEVEKLPA + cheat + description:1 penalty + code:PEKAPLGA + cheat + description:8 penalties + code:AEKAPLGE + cheat + description:16 penalties + code:AOKAPLGA + +cartridge sha256:429c833eb61c0728b0d9335c61f4bd8d3fb19c3bf8a18564917bf75526f104af + title:Heisei Tensai Bakabon (Japan) + cheat + description:Invincibility + code:ESKGLIEY + cheat + description:Infinite health + code:SGOGYPVG + cheat + description:Infinite time + code:SXKEOZSA + +cartridge sha256:1c8e9b6c4c57850d4ab1dea011e0226970034a46fa29fab1d370c01fac90538d + title:Hell Fighter (Asia) (PAL) (Unl) + cheat + description:Infinite lives + code:SZSXNSVK+SZVZXSVK + +cartridge sha256:680a56e038176c7b8deca9fb910b26b097cadd58fa553ea29f3c9836c9a4e11b + title:Hello Kitty no Ohanabatake (Japan) + cheat + description:Invincibility + code:SXSSLNSE + cheat + description:Infinite lives + code:SLONNKSO + +cartridge sha256:8e4a04076b6a728a7e65a09737776dcb9defed7922bf0437d9a89bbe8c724b55 + title:Hogan's Alley (World) + cheat + description:5 misses allowed - Game A + code:IAEKOIAP + cheat + description:20 misses allowed - Game A + code:AZEKOIAP + cheat + description:Infinite misses allowed - all games + code:AAOGETPA + cheat + description:Each miss counts as 2 - all games + code:ZAOGETPA + cheat + description:Infinite misses allowed - all games (alt) + code:00B3:00 + +cartridge sha256:1c1ad2992f728c7fb6a8f3980b1a0f8e01e5b24a0c43c713300846d87be5987a + title:Holy Diver (Japan) + cheat + description:Invincibility + code:AVNYNESA + cheat + description:Infinite health + code:SXNYNESE + cheat + description:Infinite lives + code:SXKVTOVK + +cartridge sha256:3f761f529d40cf42aed60fabc0e60ecfecf528f4165948e6157b552e3bbb4f89 + title:Home Alone 2 - Lost in New York (USA) + cheat + description:Infinite power units/life points + code:SZNYSSVK + cheat + description:Become almost invincible after losing 1 life point (against most enemies, vacuum cleaner can still kill you) + code:SZSVLVVK + cheat + description:Infinite lives + code:SZEYKVVK + cheat + description:Infinite slides on pick-up + code:SZOELKVK + cheat + description:Infinite darts on pick-up + code:SZVETKVK + cheat + description:Infinite flying fists on pick-up + code:SZSAAKVK + cheat + description:Every 4 cookies count as 8 + code:AENYVGGE + cheat + description:Every 4 cookies count as 12 + code:GENYVGGE + cheat + description:Every 4 cookies count as 16 + code:AONYVGGA + cheat + description:Every 4 cookies count as 20 (extra life point) + code:GONYVGGA + cheat + description:Extra life with 5 pizza slices instead of 6 + code:IAOVUGTA + cheat + description:Extra life with 4 pizza slices + code:GAOVUGTA + cheat + description:Extra life with 3 pizza slices + code:LAOVUGTA + cheat + description:Extra life with 2 pizza slices + code:ZAOVUGTA + cheat + description:Extra life with every pizza slice + code:PAOVUGTA + cheat + description:Start with 1 life instead of 3 + code:PEEPILLA + cheat + description:Start with 5 lives + code:IEEPILLA + cheat + description:Start with 7 lives + code:YEEPILLA + cheat + description:Start with 9 lives + code:PEEPILLE + cheat + description:Start with 25 lives + code:POEPILLE + cheat + description:Start with 50 lives + code:ZUEPILLA + cheat + description:Start with 75 lives + code:LKEPILLE + cheat + description:Start with 99 lives + code:LVEPILLA + +cartridge sha256:f3ff0c50c05aa5d461c293e306e553152e63564cd09e80ae0b6dcfa97b07d073 + title:Hook (USA) + cheat + description:Infinite health - P1 + code:GZVIKIST + cheat + description:Infinite health - P2 + code:GZNSNIST + cheat + description:Infinite lives - P1 + code:SZONIEVK + cheat + description:Max health from food - P1 + code:AENIOIIA + cheat + description:Max health from food - P2 + code:AAEINTIA + cheat + description:No health from food + code:AVVIXSGZ + cheat + description:Start with 1 life + code:AEXVNTZA + cheat + description:Start with 6 lives + code:IEXVNTZA + cheat + description:Start with 9 lives + code:AEXVNTZE + cheat + description:Infinite health - P1 (alt) + code:0365:6F + cheat + description:Infinite lives - P1 (alt) + code:0367:09 + cheat + description:Max Green Balls + code:0363:63 + cheat + description:Infinite Cakes + code:0487:63 + cheat + description:Max Green Thimbles + code:0364:63 + +cartridge sha256:3991a761116131dc412fd7cfe8e70bf414d11fa4778e9dfb049ffcc9a8586cac + title:Hudson Hawk (USA) + cheat + description:Infinite health + code:SXETGYSA + cheat + description:Infinite lives + code:OZSKYYUK+OZVGZYEN + cheat + description:Infinite continues + code:OZKKEAAU+OZKGVAVK + cheat + description:Start with very little health - first life only + code:PEVKZVNY + cheat + description:Start with 1/4 health - first life only + code:AKVKZVNY + cheat + description:Start with 1/2 health - first life only + code:ANVKZVNY + cheat + description:Start with 3/4 health - first life only + code:EUVKZVNY + cheat + description:Start with 1 continue + code:PESKPTLA + cheat + description:Start with 5 continues + code:IESKPTLA + cheat + description:Start with 9 continues + code:PESKPTLE + cheat + description:Start with 1 life + code:PEVGTTIA + cheat + description:Start with 3 lives + code:LEVGTTIA + cheat + description:Start with 9 lives + code:PEVGTTIE + +cartridge sha256:53bfc94fce46a25188f84f102810406f686a7fb13fb5e4ae8f13760106acb969 + title:Hudson's Adventure Island (USA) + cheat + description:Invincibility + code:ATSKZAKZ + cheat + description:Infinite health + code:SXKKIAVG + cheat + description:Immune to rocks + code:GXNGLAKA + cheat + description:Keep weapons + code:GZXEAPSA + cheat + description:Hit anywhere + code:AAKGTOKI+AAKKYPYA+OLSGZOOO + cheat + description:Multi-jump + code:GXVAGGEI+GXVEPGEI + cheat + description:Get fruits from anywhere + code:EIUEOLEL + cheat + description:Collectable items never disappear + code:ATKAEUVI + cheat + description:Can mega-jump while at rest + code:SPEEIIEG + cheat + description:Can mega-jump while running + code:SPEETSOZ + cheat + description:Multi-mega-maxi-moon jumps + code:AAEAYIPA+AEVEZGPZ + cheat + description:Skateboard doesn't automatically move forward + code:ALSAIIEI + cheat + description:Hudson can moonwalk + code:AEKAPIPA+PEEEZIAA + cheat + description:Start with infinite lives + code:SZOEGPVG + cheat + description:Start with 1 life + code:PEEEPALA + cheat + description:Start with 6 lives + code:TEEEPALA + cheat + description:Start with 9 lives + code:PEEEPALE + +cartridge sha256:bafe68d5e6bbebb0d71432d09bed0a482215d4534778a76d471150a3bdd01b08 + title:Hunt for Red October, The (USA) (Rev A) + cheat + description:Infinite lives + code:SXEZXZVG + cheat + description:Infinite time + code:SXEUPUVK + cheat + description:Infinite horizontal torpedoes + code:SXUXYSVK + cheat + description:Infinite vertical torpedoes + code:SZUZPVVK + cheat + description:Maximum power horizontal torpedoes on pick-up + code:OZEUEKOK+AAEUVGPA + cheat + description:Maximum power vertical torpedoes on pick-up + code:OZSLNKOK+AASUSGPA + cheat + description:Start with 10 horizontal torpedoes + code:ZANLVKPO + cheat + description:Start with 50 horizontal torpedoes + code:ZLNLVKPP + cheat + description:Start with 99 horizontal torpedoes + code:LTNLVKPP + cheat + description:Start with 5 vertical torpedoes + code:IANUUKYA + cheat + description:Start with 50 vertical torpedoes + code:ZLNUUKYA + cheat + description:Start with 99 vertical torpedoes + code:LTNUUKYA + cheat + description:Start with 5 caterpillars + code:IEELSKZA + cheat + description:Start with 50 caterpillars + code:ZUELSKZA + cheat + description:Start with 99 caterpillars + code:LVELSKZA + cheat + description:Start with 5 ECM's + code:IEEUXKZA + cheat + description:Start with 50 ECM's + code:ZUEUXKZA + cheat + description:Start with 99 ECM's + code:LVEUXKZA + cheat + description:Start with 1 life + code:PEVLYAIA + cheat + description:Start with 10 lives + code:ZEVLYAIE + +cartridge sha256:770abf58074764db12aade941ab1a389a818b8ff94d95f4b4b4913912b1f40b5 + title:Hydlide (USA) + cheat + description:Boost strength, life, magic + code:AZKAAVZE + cheat + description:Super boost strength, life, magic + code:GTKAAVZA + cheat + description:Don't take damage from most enemies + code:SXSGYYSA + cheat + description:Rapid healing + code:AEUEKVIA + cheat + description:Rapid magic healing + code:AANOVZZA + cheat + description:Infinite life + code:0038:64 + cheat + description:Max STR + code:0039:64 + cheat + description:Max EXP + code:003A:64 + cheat + description:Max Magic + code:003B:64 + cheat + description:Have the Sword + code:0059:FF + cheat + description:Have the Shield + code:005A:FF + cheat + description:Have the Lamp + code:005B:FF + cheat + description:Have the Cross + code:005C:FF + cheat + description:Have the Pot + code:005D:FF + cheat + description:Have the Medicine + code:005E:FF + cheat + description:Have the Key + code:005F:FF + cheat + description:Have the Ruby + code:0060:FF + cheat + description:Have the Ring + code:0061:FF + cheat + description:Have the Jewel + code:0062:FF + cheat + description:Have 3 Fairies + code:0063:FF+0064:FF+0065:FF + +cartridge sha256:002bb62441c1625051555109bce93ff2e2a2badb534a350b6d17ad0d7e7ef023 + title:Ice Climber (USA, Europe) + cheat + description:Invincibility + code:ATKSALAZ + cheat + description:Infinite lives + code:OKEIPGVS + cheat + description:Super-jump + code:GPUKOAZX + cheat + description:Enemies bump you instead of killing you + code:ELKITLEY + cheat + description:Double speed + code:VNSKXUNN+ZESKULPA + cheat + description:Triple speed + code:SNSKXUNN+LESKULPA + cheat + description:Start with 1 life + code:AEXKTGLA + cheat + description:Start with 6 lives + code:IEXKTGLA + cheat + description:Start with 9 lives + code:AEXKTGLE + +cartridge sha256:3775c1184419c0786841c5b4f2694b2a15e181678f92e75fb9b71bfb5668c7b3 + title:Ikari Warriors (USA) (Rev A) + cheat + description:Invincibility + code:SXVYAUGK + cheat + description:Invincibility (except against bombs) + code:ESVLZYEY + cheat + description:Invincibility (blinking) + code:KAXTLAEA + cheat + description:Infinite lives + code:SXSNZTVI + cheat + description:Infinite Missiles for Tank + code:SXXNVUVS + cheat + description:Infinite Bullets + code:SZONZSVS + cheat + description:Infinite Grenades + code:SXEYZSVS + cheat + description:Enemies die automatically + code:AAKLAYLY+AAOPYOGP+ASUUSPEL+GXOEATEP + cheat + description:Hit anywhere (except tanks and helicopters) + code:AEXUOPPA+LUXUUPLO+OKXUEOPX + cheat + description:Start with 1 life + code:PAUYPTLA + cheat + description:Start with 6 lives + code:TAUYPTLA + cheat + description:Start with 9 lives + code:PAUYPTLE + cheat + description:Start with 50 Bullets + code:ZUNNLZLT + cheat + description:Start with 99 Grenades + code:LTEYALZL + cheat + description:Start with 25 Grenades + code:PPEYALZU + cheat + description:Infinite lives - P1 + code:00E4:09 + cheat + description:Infinite lives - P2 + code:00E5:09 + cheat + description:Infinite Bullets - P1 + code:067F:63 + cheat + description:Infinite Bullets - P2 + code:0682:63 + cheat + description:Infinite Grenades - P2 + code:0680:63 + cheat + description:Infinite Grenades - P1 + code:0681:63 + cheat + description:Infinite Fuel for tank - P1 + code:0683:FF + cheat + description:Infinite Fuel for tank - P2 + code:0684:FF + cheat + description:Have 3-Way Shot, B Grenades, Super Speed, Knife - P1 + code:0674:DF + cheat + description:Have F Shot, Long Range, Rapid Fire, B Grenades, Super Speed, Knife - P1 + code:0674:EF + cheat + description:Have 3-Way Shot, B Grenades, Super Speed, Knife - P2 + code:0675:DF + cheat + description:Have F Shot, Long Range, Rapid Fire, B Grenades, Super Speed, Knife - P2 + code:0675:EF + +cartridge sha256:294f70829b72f3d1b6c81be92b542e96fec1a243d16dfd338a4226b97ad09732 + title:Ikari Warriors (USA) + cheat + description:Invincibility + code:SXVYAUGK + cheat + description:Invincibility (except against bombs) + code:ESVLZYEY + cheat + description:Invincibility (blinking) + code:KAXTLAEA + cheat + description:Infinite lives + code:SXSNZTVI + cheat + description:Infinite Missiles for Tank + code:SXXNVUVS + cheat + description:Infinite Bullets + code:SZONZSVS + cheat + description:Infinite Grenades + code:SXEYZSVS + cheat + description:Enemies die automatically + code:AAKLAYLY+AAOPYOGP+ASUUSPEL+GXOEATEP + cheat + description:Hit anywhere (except tanks and helicopters) + code:AEXUOPPA+LUXUUPLO+OKXUEOPX + cheat + description:Start with 1 life + code:PAUYPTLA + cheat + description:Start with 6 lives + code:TAUYPTLA + cheat + description:Start with 9 lives + code:PAUYPTLE + cheat + description:Start with 50 Bullets + code:ZUNNLZLT + cheat + description:Start with 99 Grenades + code:LTEYALZL + cheat + description:Start with 25 Grenades + code:PPEYALZU + cheat + description:Infinite lives - P1 + code:00E4:09 + cheat + description:Infinite lives - P2 + code:00E5:09 + cheat + description:Infinite Bullets - P1 + code:067F:63 + cheat + description:Infinite Bullets - P2 + code:0682:63 + cheat + description:Infinite Grenades - P2 + code:0680:63 + cheat + description:Infinite Grenades - P1 + code:0681:63 + cheat + description:Infinite Fuel for tank - P1 + code:0683:FF + cheat + description:Infinite Fuel for tank - P2 + code:0684:FF + cheat + description:Have 3-Way Shot, B Grenades, Super Speed, Knife - P1 + code:0674:DF + cheat + description:Have F Shot, Long Range, Rapid Fire, B Grenades, Super Speed, Knife - P1 + code:0674:EF + cheat + description:Have 3-Way Shot, B Grenades, Super Speed, Knife - P2 + code:0675:DF + cheat + description:Have F Shot, Long Range, Rapid Fire, B Grenades, Super Speed, Knife - P2 + code:0675:EF + +cartridge sha256:119f865684be58f37101b431975c827b2ad9340c0f2d3d9fc3153ee1213ee55e + title:Ikari Warriors II - Victory Road (USA) + cheat + description:Infinite health + code:OUOUIUOO + cheat + description:Don't take damage from most enemies + code:GXOLYLST + cheat + description:Start with half normal health + code:AUNYIYAT + cheat + description:Maximum weapon power on pick-up + code:OZUXVEPV+GAUXNAPA + cheat + description:Infinite health (alt) + code:06D1:32 + cheat + description:Infinite hearts + code:00F8:80 + cheat + description:Have Machine Gun + code:06C3:04 + cheat + description:Start with and keep Arrow + code:00F2:01 + cheat + description:Start with and keep Bazooka + code:06C5:04 + cheat + description:Start with and keep Boomerang + code:06C7:04 + cheat + description:Start with and keep Earthquake + code:00EC:01 + cheat + description:Start with and keep Elixir + code:00F6:01 + cheat + description:Start with and keep Grenades + code:06CB:04 + cheat + description:Start with and keep Land Mines + code:06CD:04 + cheat + description:Start with and keep Lightning + code:00EA:01 + cheat + description:Start with and keep Shield + code:00F0:01 + cheat + description:Start with and keep Sword + code:06C9:04 + cheat + description:Start with and keep Time Stopper + code:00F4:01 + cheat + description:Start with and keep Wings + code:00EE:01 + +cartridge sha256:181163b590a581b6d04baaedb815429a2342ded27b3fb7f2514661d1fd47c1cc + title:Ikari III - The Rescue (USA) + cheat + description:Invincibility + code:SZKLUZAX + cheat + description:Infinite health + code:SLSUNESO + cheat + description:Infinite lives + code:AEUGNYPA + cheat + description:Infinite lives (alt) + code:SUUKKNSO + cheat + description:Immune to most kicks and punches + code:GZSUOAST + cheat + description:3-way firing, instead of punching + code:YESKVGPA + cheat + description:Always throw grenades instead of punches + code:PESKVGPE + cheat + description:1 life after continue + code:PEXKZLLA + cheat + description:6 lives after continue + code:TEXKZLLA + cheat + description:9 lives after continue + code:PEXKZLLE + cheat + description:Start with 1 life + code:PEOKUALA + cheat + description:Start with 6 lives + code:TEOKUALA + cheat + description:Start with 9 lives + code:PEOKUALE + +cartridge sha256:7032a94d140339f9d6603accc9fed2846f5bbb781659cdff869d4b5f137d4e4a + title:Image Fight (USA) + cheat + description:Invincibility + code:ENKXYGEI+ENOPLPEI + cheat + description:Infinite lives - both players + code:SXSZTPVG + cheat + description:Never lose Pods + code:ATSLTKOZ + cheat + description:Start with V Cannon + code:PAELGGAA + cheat + description:Start with Reflecting Ball + code:ZAELGGAA + cheat + description:Start with Drilling Laser + code:LAELGGAA + cheat + description:Start with Seeking Missile + code:GAELGGAA + cheat + description:Start with Seeking Laser + code:IAELGGAA + cheat + description:Start with 1 life - both players + code:PAVXLPLA + cheat + description:Start with 6 lives - both players + code:TAVXLPLA + cheat + description:Start with 9 lives - both players + code:PAVXLPLE + cheat + description:Start at Combat Simulation Stage 2 + code:PAVZLPAA + cheat + description:Start at Combat Simulation Stage 3 + code:ZAVZLPAA + cheat + description:Start at Combat Simulation Stage 4 + code:LAVZLPAA + cheat + description:Start at Combat Simulation Stage 5 + code:GAVZLPAA + cheat + description:Start at Real Combat - 1st Target + code:IAVZLPAA + cheat + description:Start at Real Combat - 2nd Target + code:TAVZLPAA + +cartridge sha256:8bc6a252778c2909a97b3fff185c5ff2a1786afe5e8237098f15fe3eaf23adab + title:Immortal, The (USA) + cheat + description:Enemy's fatigue level doesn't go down + code:GZOLIXVK + cheat + description:Your fatigue level doesn't go down + code:GZOUIXVK + cheat + description:Your fatigue level goes down faster + code:YLEUIXYN + cheat + description:Your fatigue level goes down slower + code:NYEUIXYN + cheat + description:Don't lose energy from fighting + code:SZSLTXVK + cheat + description:Your fatigue level never rises + code:SZNLPXVV + cheat + description:More damage from fireballs + code:ZAKSIYPA + cheat + description:Instant kills on enemies + code:0362:00 + cheat + description:Infinite health in battle sequences + code:0363:0F + cheat + description:Infinite Gold + code:042C:FF + +cartridge sha256:c42fc592821b474b486ae32d1d63e8938f1735a6d45db026f7b78b2ec51427ac + title:Incredible Crash Dummies, The (USA) + cheat + description:Invincibility + code:EIUXYYEY + cheat + description:Infinite health + code:KZVGGNKE + cheat + description:Infinite lives + code:KZNKANKE + cheat + description:Invincibility (blinking) + code:053C:01 + +cartridge sha256:79c03fec3f459ac6e762c27d8f08debe6589b01df21919ef69645870a16723b3 + title:Indiana Jones and the Last Crusade (USA) (UBI Soft) + cheat + description:Infinite health (you can get trapped in certain areas) + code:VYONKZGE + cheat + description:Infinite time + code:AEEOYTPA + cheat + description:Infinite credits + code:SXXXIEVK + cheat + description:Infinite lives + code:KYSTEGGE + cheat + description:Infinite lives on bike section + code:SZUEEIVG + cheat + description:More lives on ship section + code:PAVAGYIE + cheat + description:Fewer lives on ship section + code:PAVAGYIA + cheat + description:More lives on tank section + code:PAEPIITE + cheat + description:Fewer lives on tank section + code:PAEPIITA + cheat + description:More lives on castle section + code:PEXPTALE + cheat + description:Fewer lives on castle section + code:PEXPTALA + cheat + description:Heart does nothing (may goof up energy bar) + code:AEKPXLPA + cheat + description:Super-jump + code:IAVTKAPA + cheat + description:Mega-jump + code:PAVTKAPE + cheat + description:Continue with 1 life + code:PEUZPALA + cheat + description:Continue with 5 lives + code:IEUZPALA + cheat + description:Continue with 7 lives + code:YEUZPALA + cheat + description:Continue with 9 lives + code:PEUZPALE + cheat + description:Start with 1 life + code:PAVKGALA + cheat + description:Start with 5 lives + code:IAVKGALA + cheat + description:Start with 7 lives + code:YAVKGALA + cheat + description:Start with 9 lives + code:PAVKGALE + cheat + description:Start on level 2 (after completing the level you'll go back to level 1) + code:PANGPAAA + cheat + description:Start on level 3 (after completing the level you'll go back to level 1) + code:ZANGPAAA + cheat + description:Start on level 4 (after completing the level you'll go back to level 1) + code:LANGPAAA + cheat + description:Start on level 5 (after completing the level you'll go back to level 1) + code:GANGPAAA + cheat + description:Start on level 6 (after completing the level you'll go back to level 1) + code:IANGPAAA + +cartridge sha256:5348f7f88695867de428b38eb6a7f724f5f97110c383567d7e4d1f5a2d8b612f + title:Indiana Jones and the Last Crusade (USA) (Taito) + cheat + description:Infinite health + code:SAOOLOIE + +cartridge sha256:884765e5df86042211191f7e7e4653255425e3da70a9dec6f4a9336c07b5f258 + title:Indiana Jones and the Temple of Doom (USA) (Rev A) + cheat + description:Infinite lives + code:SZEXOKVK + cheat + description:Infinite time + code:SZXZAEVK + cheat + description:Always keep Sword + code:SZSZGUVK + cheat + description:Always keep Gun + code:SZUXZVVK + cheat + description:Start with less time + code:GLKUXGLV+LVEXUUGL+LTOXVKGL + cheat + description:Start with 1 life + code:AEKLULGA + cheat + description:Start with 10 lives + code:PEKLULGE + cheat + description:Start with 15 lives + code:TEKLULGE + cheat + description:Start on level 2 + code:PPKLEKYA + cheat + description:Start on level 4 + code:IPKLEKYA + cheat + description:Start on level 6 + code:PPKLEKYE + cheat + description:Start on level 8 + code:IPKLEKYE + cheat + description:0 Maps left + code:012F:00 + cheat + description:Have all 3 Keys + code:011D:B0 + +cartridge sha256:8125d69b66dd7784246156bb669542924f1c2b7f53b8d325ffcbaa74746d14ff + title:Indiana Jones and the Temple of Doom (USA) + cheat + description:Infinite lives + code:SZEXOKVK + cheat + description:Infinite time + code:SZXZAEVK + cheat + description:Always keep Sword + code:SZSZGUVK + cheat + description:Always keep Gun + code:SZUXZVVK + cheat + description:Start with less time + code:GLKUXGLV+LVEXUUGL+LTOXVKGL + cheat + description:Start with 1 life + code:AEKLULGA + cheat + description:Start with 10 lives + code:PEKLULGE + cheat + description:Start with 15 lives + code:TEKLULGE + cheat + description:Start on level 2 + code:PPKLEKYA + cheat + description:Start on level 4 + code:IPKLEKYA + cheat + description:Start on level 6 + code:PPKLEKYE + cheat + description:Start on level 8 + code:IPKLEKYE + cheat + description:0 Maps left + code:012F:00 + cheat + description:Have all 3 Keys + code:011D:B0 + +cartridge sha256:0bb401bbd0cae2758b2bd355cd3cac3cc26a01950859c830b3b122bd379f2463 + title:Infiltrator (USA) + cheat + description:Infinite time + code:SZKLIKVK + cheat + description:Never lose Grenades outside buildings + code:SXKXXIVG + cheat + description:Never lose Grenades inside buildings + code:SZVKAIVG + cheat + description:Never lose Spray outside buildings + code:SXUXKIVG + cheat + description:Never lose Spray inside buildings + code:SZUKYIVG + cheat + description:Start with less time + code:ILOULXPL + cheat + description:Start with more Grenades + code:ZPSLPXZA + cheat + description:Start with fewer Grenades + code:IASLPXZA + cheat + description:Start with no Grenades + code:AASLPXZA + cheat + description:Start with less Spray + code:LPKUIZTZ + cheat + description:Start with no Spray + code:AAKUIZTZ + +cartridge sha256:0f406a7c853b919ed880868420808b945855146db9817ebc3102f08da13fa703 + title:Insector X (Japan) + cheat + description:Invincibility + code:00CA:00 + cheat + description:Infinite lives + code:00D8:03 + cheat + description:Max shot power-up + code:00CC:06 + +cartridge sha256:6fac8ea87f7eea5e9bf7b838ff92c2fa3369908c866631340ec489beacdcbf3b + title:Iron Tank - The Invasion of Normandy (USA) + cheat + description:Infinite health + code:SLUVKESO + cheat + description:Infinite lives + code:OIOGIIPA+SXUKTKVK + cheat + description:Start with 1 life + code:OIOGIIPA+AAUKGGZA + cheat + description:Start with 6 lives + code:OIOGIIPA+IAUKGGZA + cheat + description:Start with 9 lives + code:OIOGIIPA+AAUKGGZE + cheat + description:Infinite health (alt) + code:0306:FF + cheat + description:Infinite lives (alt) + code:01D1:09 + +cartridge sha256:aab5e0ecc46e575b1b396bd63d8fa4f3bd740061f3157a1d4afdf9f7f2dabd88 + title:IronSword - Wizards & Warriors II (USA) + cheat + description:Infinite lives + code:OXXANAVK + cheat + description:Infinite continues + code:OZUAXPVK + cheat + description:Infinite spells + code:GXXSNKVS + cheat + description:Infinite money + code:ZEOSEGAA + cheat + description:Infinite keys once one is obtained + code:SEOOTISZ + cheat + description:Super-jump + code:OTUIGLSV+PAUIILVE + cheat + description:Food gives full health + code:AEEOEAZA + cheat + description:Drink gives full health + code:AAOPNPZA + cheat + description:Fleet foot jumping + code:AASIYPLA + cheat + description:Fleet foot running + code:OXKSYUPX + cheat + description:Start with Axe and Helmet + code:LEVEXZAA + cheat + description:Start with Shield + code:ZEVAVXNY + cheat + description:Start with Ironsword + code:AAOAGUGA + cheat + description:Start on wind level + code:LEEEPZAE + cheat + description:Start on tree level + code:GOEEPZAA + cheat + description:Start on water level + code:TOEEPZAA + cheat + description:Start on outer fire level + code:IOEEPZAA + cheat + description:Start on lower earth level + code:LUEEPZAA + cheat + description:Start on lower icefire mountain + code:PUEEPZAA + cheat + description:Start a new game with full magic + code:NYEAVLAE + cheat + description:Start with 1 life + code:PENAEZLA+PESEXPLA + cheat + description:Start with 6 lives + code:TENAEZLA+TESEXPLA + cheat + description:Infinite health (disable at end of stage) + code:006A:FF + cheat + description:Infinite magic once obtained (disable at end of stage) + code:006B:FF + cheat + description:Infinite Keys + code:006C:08 + cheat + description:Infinite money (alt) + code:0096:0A+008B:64 + cheat + description:Have the Sindarin Treasures + code:00F7:0F + cheat + description:Have the Dagger + code:0067:00 + cheat + description:Have the Sword + code:0067:01 + cheat + description:Have the Long Sword + code:0067:02 + cheat + description:Have the Axe + code:0067:03 + cheat + description:Have the Large Sword + code:0067:04 + cheat + description:Have the Ironsword + code:0067:05 + cheat + description:Have the Diamond Sword + code:0067:06 + cheat + description:Have the Helmet + code:0068:01 + cheat + description:Have the Horned Helmet + code:0068:02 + cheat + description:Have the Diamond Helmet + code:0068:03 + cheat + description:Have the Large Shield + code:0069:01 + cheat + description:Have the Diamond Shield + code:0069:02 + +cartridge sha256:81311ff2507c6522172b203534f91f99749f465c8b765ac584f0e851a8bf96b2 + title:Isolated Warrior (USA) + cheat + description:Invincibility + code:OXOPKZAU+SEOPVZSZ+UVKTAYXZ + cheat + description:Infinite health + code:XTVSGGTX + cheat + description:Infinite lives + code:SZUVPAVG + cheat + description:Infinite Bombs + code:SZXOXSVK + cheat + description:More health restored on pick-up + code:TEOAAYZA + cheat + description:Less health restored on pick-up + code:PEOAAYZA + cheat + description:Start with maximum health and Bombs + code:AASVTXPA + cheat + description:Start with 1 life + code:PAXTIZLA + cheat + description:Start with 6 lives + code:TAXTIZLA + cheat + description:Start with 9 lives + code:PAXTIZLE + cheat + description:Start on Scene 2 + code:PANEGAAA+VANEYESE+VEEAZESE + cheat + description:Start on Scene 3 + code:ZANEGAAA+VANEYESE+VEEAZESE + cheat + description:Start on Scene 4 + code:LANEGAAA+VANEYESE+VEEAZESE + cheat + description:Start on Scene 5 + code:GANEGAAA+VANEYESE+VEEAZESE + cheat + description:Start on Scene 6 + code:IANEGAAA+VANEYESE+VEEAZESE + cheat + description:Invincibility (alt) + code:00E3:00 + cheat + description:Full Power Gun #1 + code:00A4:0C + cheat + description:Full Power Gun #2 + code:00A5:0C + cheat + description:Full Power Bombs + code:06A8:04 + cheat + description:Full speed + code:00DA:04 + +cartridge sha256:acc3b89bcbe3ccc2ee29d0b2eb3fb9cec143236f48d88680b462c3dfab0784bf + title:Ivan 'Ironman' Stewart's Super Off Road (USA) + cheat + description:Infinite money + code:GGUTGGOU+GGUTIGAV+KTUTTKAL + cheat + description:Infinite nitro boosts + code:AEKISPPA + cheat + description:Lots of money and full equipment + code:TEKTYGAA + cheat + description:Computer starts with no nitro boosts + code:AAUEIEPP + cheat + description:Computer starts with double nitro boosts + code:ZLUEIEPP + cheat + description:Start with double nitro boosts + code:ZLEVZSPP + cheat + description:Start with 1 life + code:PENTYGLA + cheat + description:Infinite lives - P1 + code:075D:03 + cheat + description:Infinite money - P1 + code:0305:09+0306:09+0307:09+0308:09 + cheat + description:Infinite nitro boosts - P1 + code:0310:63 + +cartridge sha256:6928e8c589d6d9cc199a7b0841877531ef53dce479e36f90ec1d9cdcbf54372d + title:Jackal (USA) + cheat + description:Invincibility - both players + code:ASUVZIEI + cheat + description:Infinite lives - both players + code:SZPTSI + cheat + description:Keep weapons after death + code:GXZTSG + cheat + description:Full weapons after death + code:LEZTKG + cheat + description:Start with 1 life - both players + code:PAPKXZ + cheat + description:Start with 9 lives - both players + code:PAPKXX + cheat + description:Invincibility - P1 + code:0053:01 + cheat + description:Invincibility - P2 + code:0531:01 + cheat + description:Infinite lives + code:0031:09 + cheat + description:Max Score + code:07E4:99+07E5:99+07E6:99 + cheat + description:Start on level 2 + code:0030:01 + cheat + description:Start on level 3 + code:0030:02 + cheat + description:Start on level 4 + code:0030:03 + cheat + description:Start on level 5 + code:0030:04 + cheat + description:Start on level 6 + code:0030:05 + +cartridge sha256:628d6696c7ac84c3ae5ab86d04b28b2fd1742076ca9478fdd5708e3bbb9f13c1 + title:Jackie Chan's Action Kung Fu (USA) + cheat + description:Invincibility + code:ESSINLEY + cheat + description:Infinite health + code:VXEGXXSE + cheat + description:Infinite special attacks + code:SXSKEXVK + cheat + description:Take less damage + code:PTYSEK + cheat + description:9 Tornado Attacks on pick-up + code:PESIKYYE + cheat + description:9 360o Spin Kicks on pick-up + code:PESIVYYE + cheat + description:9 Sky Attacks on pick-up + code:PESINYYE + cheat + description:0 Tornado Attacks on pick-up + code:AESIKYYA + cheat + description:0 180o Spin Kicks on pick-up + code:AESISNPA + cheat + description:0 360o Spin Kicks on pick-up + code:AESIVYYA + cheat + description:0 Sky Attacks on pick-up + code:AESINYYA + cheat + description:Max health from Energy Bowl + code:TAVGXZZA + cheat + description:Less health from Energy Bowl + code:PAVGXZZA + cheat + description:Infinite health (alt) + code:0702:07 + cheat + description:Infinite first special move + code:0703:05 + cheat + description:Infinite second special move + code:0705:09 + cheat + description:One hit kills on bosses + code:0039:00 + +cartridge sha256:e0d4463066d9985d51f80f8a51b1b9c5945e481ef19df48056d7648337d59095 + title:James Bond Jr (USA) + cheat + description:Invincibility + code:EINLYPEY+EYNUYPEI + cheat + description:Infinite health + code:SZNYASSO + cheat + description:Infinite weapons (Bombs, Flares, Nukes, Bullets) + code:AANNSLPA + cheat + description:Immune to most damage + code:GZVYPIST + cheat + description:Infinite lives + code:SXEKSOVK + cheat + description:Slow down rate of air loss (scuba mode) + code:YUSOENYO + cheat + description:Speed up rate of air loss + code:YESOENYO + cheat + description:Shield doesn't take damage from bullets + code:GZUYZIST + cheat + description:Start with some weapons + code:XVOTAEXE + cheat + description:Start with 2 lives + code:PANTTATA + cheat + description:Start with 15 lives + code:TANTTATE + cheat + description:Infinite Pistol ammo + code:040F:63 + cheat + description:Infinite lives + code:042C:09 + cheat + description:Infinite time (minute ten's digit) + code:01F9:09 + cheat + description:Infinite time (minute one's digit) + code:01FA:09 + cheat + description:Infinite time (second ten's digit) + code:01FB:09 + cheat + description:Infinite time (second one's digit) + code:01FC:09 + +cartridge sha256:8db2cb94dc9caec681b13b66f26590e88229245fa592e5292d097e8599ee79e0 + title:Jaws (USA) + cheat + description:Infinite lives + code:SZSATSVK + cheat + description:Infinite shells + code:SZVEYNSE + cheat + description:Collect shells from anywhere + code:AANZPTTZ + cheat + description:Don't lose shells on dying + code:SZSELSTK + cheat + description:Don't lose power on dying + code:SZSETSVK + cheat + description:99 Shells on pick-up + code:AEEZITIA + cheat + description:Jaws has no health + code:AEKEPIGP+AESEGZGP+SZKEISSE + cheat + description:Start with 1 life + code:PEOAGZLA + cheat + description:Start with double lives + code:TEOAGZLA + cheat + description:Invincibility (disable to collect items) + code:9966:07 + cheat + description:Infinite lives (alt) + code:0387:09 + cheat + description:Infinite Strobes + code:0393:09 + cheat + description:Exit stage when hit instead of dying + code:8515:3A + cheat + description:Jaws has very little health + code:0389:00 + cheat + description:Jaws is attacked without actually shooting him + code:993D:10 + +cartridge sha256:c9a3c9873a859fcbb5b7442b3decfdcab3a1457e028ae444b050a377fc92afa2 + title:Jetsons, The - Cogswell's Caper (USA) + cheat + description:Infinite lives + code:SZSLXVVK + cheat + description:Infinite hearts + code:SZEELUVK + cheat + description:Better start (more lives and hearts) + code:IEEPPILA + cheat + description:Don't lose extra hearts on dying + code:GXVLEVVK + cheat + description:2 power packs on pick-up + code:ZEVEZLPA + cheat + description:5 power packs on pick-up + code:IEVEZLPA + cheat + description:Small hearts gives full health + code:AAKAIGTA + cheat + description:Defenses don't use up powerpacks + code:GXUENESE + cheat + description:Shield uses fewer powerpacks + code:IAUAKAAZ + cheat + description:Flashlight uses fewer powerpacks + code:ZENEIYAP + cheat + description:Start with 30 powerpacks + code:AUEOGIAP + cheat + description:Start with 50 powerpacks + code:ASEOGIAP + cheat + description:Invincibility + code:0126:00 + cheat + description:Invincibility (blinking) + code:0127:02 + cheat + description:Infinite health + code:0141:03 + cheat + description:Infinite lives + code:0142:0A + +cartridge sha256:69cf1773c23606cdbd8b5e556f39c7c317100914779115a8c5c8b5dbf3fe0fcc + title:Jimmy Connors Tennis (USA) + cheat + description:Only need 15 points to win game + code:AEVTIPLA + cheat + description:Only need 30 points to win game + code:PEVTIPLA + cheat + description:Only need 40 points to win game + code:ZEVTIPLA + cheat + description:Only need 1 game to win set instead of 6 + code:AEEVAZTA + cheat + description:Only need 2 games to win set + code:PEEVAZTA + cheat + description:Only need 3 games to win set + code:ZEEVAZTA + cheat + description:Only need 4 games to win set + code:GEEVAZTA + cheat + description:Only need 5 games to win set + code:IEEVAZTA + cheat + description:Must get 2 points after 40 to win and no deuces (always shows advantage after 40) + code:EEVVIPEI + cheat + description:Don't need to win by 2 to win tiebreaker + code:PEKVGPZA + cheat + description:2 points needed to win tiebreaker instead of 7 + code:ZEUVIPYA + cheat + description:3 points needed to win tiebreaker + code:LEUVIPYA + cheat + description:4 points needed to win tiebreaker + code:GEUVIPYA + cheat + description:5 points needed to win tiebreaker + code:IEUVIPYA + cheat + description:6 points needed to win tiebreaker + code:TEUVIPYA + cheat + description:10 points needed to win tiebreaker + code:ZEUVIPYE + +cartridge sha256:509f04b745d11b8d83afb42f084179a6f2ebc87f647927432a647f0e7ee51bb5 + title:Joe & Mac (USA) + cheat + description:Invincibility + code:ESXIZTEY+ENXSGTEI + cheat + description:Infinite health + code:SZKVOKVK + cheat + description:Infinite lives - both players + code:SZNXTEVK + cheat + description:Protection from most enemy hits + code:SZKVOKVK + cheat + description:Protection from water + code:SXUVYVVK + cheat + description:Stone axe and flint do more damage to bosses + code:AAKUEAPE + cheat + description:Stone axe and flint do a lot more damage to bosses + code:YAKUEAPE + cheat + description:Stone wheel and boomerang do more damage to bosses + code:AASLOAZE + cheat + description:Stone wheel and boomerang do a lot more damage to bosses + code:APSLOAZA + cheat + description:Fire does more damage to bosses + code:APSLVAGA + cheat + description:Fire does a lot more damage to bosses + code:AZSLVAGA + cheat + description:Apple and hamburger worth nothing + code:SZVTKUSE + cheat + description:Apple and hamburger restore health to 1/2 + code:AAVTULAO + cheat + description:Start with 1/2 health (die when bar is 1/2 empty) + code:AEXZGLAO + cheat + description:Start with stone wheel instead of stone axe - P1 + code:OVUXZAET + cheat + description:Start with flint instead of stone axe - P1 + code:XVUXZAET + cheat + description:Start with fire instead of stone axe - P1 + code:UVUXZAET + cheat + description:Start with boomerang instead of stone axe - P1 + code:KVUXZAET + cheat + description:Start with 1 life instead of 3 - P1 + code:PEUXYALA + cheat + description:Start with 5 lives - P1 + code:IEUXYALA + cheat + description:Start with 7 lives - P1 + code:YEUXYALA + cheat + description:Start with 9 lives - P1 + code:PEUXYALE + cheat + description:Start somewhere in level 2 + code:ZEKZGAAA + cheat + description:Infinite health (alt) + code:0499:0F + cheat + description:One hit kills on bosses + code:064D:00 + +cartridge sha256:ec54ed32302aaeb2fa6e0d7e2ca3ea2d8df888e77859e158298ecb2fa322178e + title:Joshua & the Battle of Jericho (USA) (v6.0) (Unl) + cheat + description:Exit always open + code:075F:05+003F:FF + cheat + description:Infinite Bombs + code:003E:01 + cheat + description:Immune to explosions (disable at end of level) + code:004B:C2 + +cartridge sha256:5b7afe0ff1fcf538fec60d085aa759522a2ab1cce511a6f210b672a256a87a8a + title:Joshua & the Battle of Jericho (USA) (v5.0) (Unl) + cheat + description:Exit always open + code:075F:05+003F:FF + cheat + description:Infinite Bombs + code:003E:01 + cheat + description:Immune to explosions (disable at end of level) + code:004B:C2 + +cartridge sha256:0417d7caec593852823b94f5520caea3745a28c9dac68e30d2c5e6f5545a9757 + title:Journey to Silius (USA) + cheat + description:Invincibility + code:SZXTSAAX+SXUTKAAX + cheat + description:Invincibility after first hit (blinking) + code:SZOAPAVG + cheat + description:Infinite health + code:SZUVUZSA + cheat + description:Infinite weapon power + code:SZUAUTSA + cheat + description:Infinite lives + code:SXNGYLVG + cheat + description:Protection against most aliens + code:OTUVOZSV + cheat + description:Some aliens are tougher + code:AAXTKAZE + cheat + description:Some aliens are weaker + code:PAXTKAZA + cheat + description:Mega-jump + code:TOOETOLA + cheat + description:Speed jump + code:AZVALPPA+EVNEYENY + cheat + description:Super speed + code:LPSEYPGA+KVNELEKN + cheat + description:1 life after continue + code:PEVIULLA + cheat + description:6 lives after continue + code:TEVIULLA + cheat + description:9 lives after continue + code:PEVIULLE + cheat + description:Start with all six weapons + code:YOKSOGZE + cheat + description:Start with Machine Gun + code:PEKSOGZA + cheat + description:Start with Laser Gun + code:GEKSOGZA + cheat + description:Start with Homing Missiles + code:AEKSOGZE + cheat + description:Start with Grenade Launcher + code:AOKSOGZA + cheat + description:Start with Machine Gun and Laser Gun + code:IEKSOGZA + cheat + description:Start with 1 life + code:PAOSOTLA + cheat + description:Start with 6 lives + code:TAOSOTLA + cheat + description:Start with 9 lives + code:PAOSOTLE + cheat + description:Infinite health (alt) + code:00B0:0F + cheat + description:Infinite lives (alt) + code:0053:09 + cheat + description:Infinite weapon power (alt) + code:00B1:3F + cheat + description:Have Machine Gun + code:00B8:01 + cheat + description:Have Shot Gun + code:00B8:02 + cheat + description:Have Laser Gun + code:00B8:03 + cheat + description:Have Homing Missile + code:00B8:04 + cheat + description:Have Grenade Launcher + code:00B8:05 + cheat + description:One hit kills on bosses + code:040F:00+04FF:00 + cheat + description:Start on stage 2 + code:0170:01 + cheat + description:Start on stage 3 + code:0170:02 + cheat + description:Start on stage 4 + code:0170:03 + cheat + description:Start on stage 5 (final stage) + code:0170:04 + +cartridge sha256:8471a6b7c7c7d6c7be0ee278778e2d25dc91462db22643395787eaaeb6e320c1 + title:Joust (USA) + cheat + description:Infinite lives + code:SXXKKZVI + cheat + description:Turbo flying + code:PASGKGAA + cheat + description:Heavens above? + code:GXVKOZSP + cheat + description:Start with 1 life + code:PEOGLAIA + cheat + description:Start with 9 lives + code:ZEOGLAIE + cheat + description:Start on last level reached + code:GXSKTASA+GXSKGASA+GXVGGASA + +cartridge sha256:8d36c0923103f370eb9fab5caeb2a8307cd1c7a30030db69bd5bc4f5ca46b1d2 + title:Jovial Race (Asia) (PAL) (Unl) + cheat + description:Infinite lives + code:SZNOUKVK + cheat + description:Start with 5 lives + code:IAVEZLLA + cheat + description:Start with 10 lives + code:ZAVEZLLE + cheat + description:Sart with 100 lives + code:GTVEZLLA + +cartridge sha256:a7bf6adcd838f055405963741dd3368730b0f9dc125ae7071832a9305a4c7292 + title:Jovial Race (Unknown) (Unl) + cheat + description:Infinite lives + code:SZNOUKVK + cheat + description:Start with 5 lives + code:IAVEZLLA + cheat + description:Start with 10 lives + code:ZAVEZLLE + cheat + description:Sart with 100 lives + code:GTVEZLLA + +cartridge sha256:e5bcb8838f567f485c6f872e9695d2e3ef676f4bcda1c32d51d56008efb96e7a + title:Jungle Book, The (USA) + cheat + description:Infinite lives + code:GZVEOSSE + cheat + description:Infinite time + code:AAVEEYPA + cheat + description:Infinite weapons + code:PENEEIAA + cheat + description:Need 2 gems to finish levels 1, 3, 4, 7, 9 + code:ZEKKULAP+SXXNLKOU + cheat + description:Need 4 gems to finish levels 1, 3, 4, 7, 9 + code:GEKKULAP+SXXNLKOU + cheat + description:Need 8 gems to finish levels 1, 3, 4, 7, 9 + code:AEKKULAO+SXXNLKOU + cheat + description:Start practice level with 1 life + code:PAEGVGTA + cheat + description:Start practice level with 3 lives + code:LAEGVGTA + cheat + description:Start practice level with 9 lives + code:PAEGVGTE + cheat + description:Start normal level with 1 life + code:PAEGNGIA + cheat + description:Start normal level with 3 lives + code:LAEGNGIA + cheat + description:Start normal level with 9 lives + code:PAEGNGIE + cheat + description:Start with 5 of each weapon + code:IAVYZLAA + cheat + description:Start with 10 of each weapon + code:APVYZLAA + cheat + description:Start with 20 of each weapon + code:AZVYZLAA + cheat + description:Start with 30 of each weapon + code:ALVYZLAA + cheat + description:Start with 90 of each weapon + code:EPVYZLAA + +cartridge sha256:49fe0c49cd0a2841ae9c8ae5aa19f710d187ee6931a1e531d3bff19772ca4af0 + title:Jurassic Park (USA) + cheat + description:Invincibility + code:EIUZUAEY + cheat + description:Infinite health + code:SZVGZOSE + cheat + description:Immune to most attacks + code:ATVGZOSA + cheat + description:Infinite lives (first two levels only) + code:GZEULOVK + cheat + description:Infinite ammo on pick-up + code:GZUXXKVS + cheat + description:More bullets picked up from small dinosaurs + code:PAVPAGZE + cheat + description:Fewer bullets picked up from small dinosaurs + code:PAVPAGZA + cheat + description:3-ball bolas picked up (from small dinosaurs instead of normal bullets) + code:VEXASASA+VEUAXASA + cheat + description:Explosive multi-shots (from small dinosaurs instead of normal bullets) + code:NEXASASA+NEUAXASA + +cartridge sha256:f40341cf7e76480465ba8ab2d09e44644c3e3af7d647dc04c8b38357b26e014a + title:Just Breed (Japan) + cheat + description:No health - all enemies + code:69E3:00+69E4:00+69E5:00+69E6:00+69DA:00+69DB:00+69DC:00+69DD:00+69DE:00+69DF:00+69E0:00+69E1:00+69E2:00 + cheat + description:Lots of EXP after battle + code:6F6E:FF + cheat + description:Max EXP after battle + code:6F6E:FF+6F6F:FF + cheat + description:Max gold after battle + code:6F6C:FF+6F6D:FF + cheat + description:Max Health (Swordsman/Archer, Etc. 1) + code:69C4:FF + cheat + description:Max Magic (Swordsman/Archer, Etc. 1) + code:6A04:FF + cheat + description:Max Health (Swordsman/Archer, Etc. 2) + code:69C6:FF + cheat + description:Max Magic (Swordsman/Archer, Etc. 2) + code:6A06:FF + cheat + description:Max Health (Swordsman/Archer, Etc. 3) + code:69C5:FF + cheat + description:Max Magic (Swordsman/Archer, Etc. 3) + code:6A05:FF + cheat + description:Max Health (Swordsman/Archer, Etc. 4) + code:69C3:FF + cheat + description:Max Magic (Swordsman/Archer, Etc. 4) + code:6A03:FF + +cartridge sha256:2ae0a99b457a6d00ff0b241aa08f98d40c5c5ed45e634a7ed934b386bbd17a12 + title:Kabuki - Quantum Fighter (USA) + cheat + description:Invincibility + code:AVUUZPSZ+ESUZGAEY + cheat + description:Infinite health + code:VZNGNNSE + cheat + description:Infinite chip power + code:SXEUAESU + cheat + description:Infinite lives + code:SZVGSNSE + cheat + description:Don't lose a life from health loss + code:AAVGKYPA + cheat + description:Don't lose a life from timer + code:AASSAAPA + cheat + description:1 continue + code:PENUXLZA + cheat + description:6 continues + code:IENUXLZA + cheat + description:9 continues + code:AENUXLZE + cheat + description:Slower timer + code:NYXIZEYU + cheat + description:Faster timer + code:YZXIZEYU + cheat + description:Special weapons use minimum chip power + code:SXEUAESU+AOEUPEYA + cheat + description:Start with maximum health + code:YENUNUZE+YEXLLUZE + cheat + description:Start with less health + code:IENUNUZA+IEXLLUZA + cheat + description:Start with 1 life + code:AENLSLZA + cheat + description:Start with 6 lives + code:IENLSLZA + cheat + description:Start with 9 lives + code:AENLSLZE + cheat + description:Invincibility (blinking) + code:0089:03 + cheat + description:Infinite health (alt) + code:068C:0A + cheat + description:Infinite lives (alt) + code:06C0:09 + cheat + description:Infinite time + code:0691:09 + +cartridge sha256:204b5eb443dc8f599d54e242352ba299c05015e5571f74307d78748af3d5f960 + title:Kame no Ongaeshi - Urashima Densetsu (Japan) + cheat + description:Invincibility + code:OXNGYLEN+SENKPUVK + +cartridge sha256:d67817e44f3a421a78ce4217a0660ee375ea162f1465a28da77659dfa46f8f7c + title:Karate Champ (USA) (Rev A) + cheat + description:One hit wins round + code:0069:20 + cheat + description:One hit wins stage + code:005D:02 + +cartridge sha256:54c366ec62c0faec3d5619f62bad73092996a26e674f58819e9b76433cc04e15 + title:Karate Champ (USA) + cheat + description:One hit wins round + code:0069:20 + cheat + description:One hit wins stage + code:005D:02 + +cartridge sha256:8aa5c70100080adf0f6d8945ea10382f3986b99d41e010c356991dfe061eaa8d + title:Karate Kid, The (USA) + cheat + description:Infinite health + code:SZSUYZSA + cheat + description:Infinite chances (lives) + code:SZOEKAVG + cheat + description:Infinite Crane Kicks + code:SXEXLYVG + cheat + description:Infinite Drum Punches on pick-up + code:SZNXAYVG + cheat + description:Hit anywhere + code:ASVOKAEL+GXVOSALA + cheat + description:Prevent girl from moving in final stage + code:AAUXOGPA + cheat + description:Start with 1 chance + code:PENEZTLA + cheat + description:Start with 6 chances + code:TENEZTLA + cheat + description:Start with 9 chances + code:PENEZTLE + cheat + description:Start with 8 Crane Kicks - 1P game + code:AAKVUGGE + cheat + description:Start with 8 Crane Kicks - 2P game + code:AAKVKGGE + cheat + description:Start with 5 Crane Kicks - P1, one on one game + code:IAKVSGAA + cheat + description:Start on stage 2 - 1P game + code:ZAKVVGPA + cheat + description:Start on stage 2 - 2P game + code:ZAKVNGPA + cheat + description:Start on stage 3 - 1P game + code:LAKVVGPA + cheat + description:Start on stage 3 - 2P game + code:LAKVNGPA + cheat + description:Start on stage 4 - 1P game + code:GAKVVGPA + cheat + description:Start on stage 4 - 2P game + code:GAKVNGPA + cheat + description:Infinite health (alt) + code:0085:0F + cheat + description:Infinite Drum Punches (alt) + code:0089:63 + cheat + description:Infinite Crane Kicks (alt) + code:008A:63 + cheat + description:Enemy has no health + code:008B:00 + +cartridge sha256:4ece74fde0b86ecef96d1909c517f55f2da71fd00e29102b8f2780606606e777 + title:Karnov (USA) + cheat + description:Invincibility after one hit + code:ASENYZEI + cheat + description:Invincibility + code:SZVKNLSA+SXEGXLSA+SZNGULSA + cheat + description:Infinite lives + code:SXKISXVK + cheat + description:Infinite time + code:GZVZNIVG + cheat + description:Jump higher + code:ZXLNTS + cheat + description:Gain 3 of most items + code:LEEGOYPA + cheat + description:Gain 97 of most items + code:NOEGOYPA + cheat + description:Never lose most items + code:AEOKSYPA + cheat + description:Start with 1 life + code:AAOSIAZA+AESIVTZA + cheat + description:Start with 6 lives + code:IAOSIAZA+IESIVTZA + cheat + description:Start with 9 lives + code:AAOSIAZE+AESIVTZE + cheat + description:Start on stage 2 + code:PAUSAAAA + cheat + description:Start on stage 3 + code:ZAUSAAAA + cheat + description:Start on stage 4 + code:LAUSAAAA + cheat + description:Start on stage 5 + code:GAUSAAAA + cheat + description:Start on stage 6 + code:IAUSAAAA + cheat + description:Start on stage 7 + code:TAUSAAAA + cheat + description:Start on stage 8 + code:YAUSAAAA + cheat + description:Start on stage 9 + code:AAUSAAAE + cheat + description:Invincibility after one hit (blinking) (alt) + code:0069:FA + cheat + description:Infinite lives (alt) + code:040B:09 + cheat + description:Infinite time (alt) + code:0094:A7 + cheat + description:Have 99 Ks + code:00BA:99 + cheat + description:Have Double Flame Shot + code:0065:01 + cheat + description:Have Triple Flame Shot + code:0065:02 + +cartridge sha256:7a406a58cf781b9ceb87f4266dca812a271bfe1f42aa392864e8bc404b2575e1 + title:Kekkyoku Nankyoku Daibouken (Japan) + cheat + description:Infinite time + code:SZKNALVT + +cartridge sha256:23bf669afb3125d72f352848628e201607b4cece974cce86f2558a1812056ece + title:Kick Master (USA) + cheat + description:Invincibility + code:APOSXTSA+SZOIOVSE+TAOSUTXI + cheat + description:Invincibility after one hit + code:OZVZOLEN + cheat + description:Infinite health + code:SZOIOVSE + cheat + description:Infinite magic points + code:SUELOISP + cheat + description:Infinite lives + code:SXULYUVK+OXUSZLEN + cheat + description:Don't flash at all after getting hit + code:AAOSOVGL + cheat + description:Barely flash at all after getting hit + code:IAOSOVGL + cheat + description:Don't flash as long after getting hit + code:IPOSOVGL + cheat + description:Start with more EXP and magic points + code:ITUSLLAT + cheat + description:Start with twice as much health + code:EEVYEIAG + cheat + description:Start with half health + code:AXVYEIAG + cheat + description:Start with very little health + code:LEVYEIAG + cheat + description:Start with 1 life + code:PAXSGLLA + cheat + description:Start with 5 lives + code:IAXSGLLA + cheat + description:Start with 9 lives + code:PAXSGLLE + +cartridge sha256:4a9544bb41869e88ec0610a799b5ce9c7d89bf9a48198923ea7ba22f385ea349 + title:Kickle Cubicle (USA) + cheat + description:Invincibility + code:SEEXPAOL+SANXAPOL + cheat + description:Infinite lives + code:SXEAATVG + cheat + description:Infinite time + code:SXNGSVVK + cheat + description:Infinite time (alt) + code:ANTKVT + cheat + description:Faster timer + code:YENKXVZA + cheat + description:Slower timer + code:YENKXVZE + cheat + description:Win level now + code:ESSATLEY + cheat + description:Start on land 2 + code:GZKATXSE+GZUISOSE+PAUIOPAA + cheat + description:Start on land 3 + code:GZKATXSE+GZUISOSE+ZAUIOPAA + cheat + description:Start on land 4 + code:GZKATXSE+GZUISOSE+LAUIOPAA + +cartridge sha256:56f1fe3a7881b2e9d69cd33a0971b2f26247e964c3c7dd4a6019715425ff2256 + title:Kid Icarus (USA, Europe) + cheat + description:Invincibility + code:OTXSVLON + cheat + description:99 Hammers on pick-up + code:EOSTEXOZ+KNSTOZPA + cheat + description:Small hearts worth 135 + code:NAKSXTPA + cheat + description:Small hearts worth 2 + code:ZAKSXTPA + cheat + description:Small hearts worth 5 + code:IAKSXTPA + cheat + description:Big hearts worth 255 + code:NYKSSVZA + cheat + description:Big hearts worth 20 + code:GPKSSVZA + cheat + description:Lave restores health + code:VVXGUYVG + cheat + description:Immune to becoming eggplant + code:AAUEVAPA + cheat + description:No damage from Medusa + code:SZSLAPSA + cheat + description:No damage from floor hazards + code:SKXGUYVG + cheat + description:Get best ending with 8uuuuu uuuuuu uuuuuu uuuuuu code + code:PEEEZPAA + +cartridge sha256:a11eec5762a029c95a5d496c0671b73e663225be50a5b1e89f16f380637b6665 + title:Kid Klown in Night Mayor World (USA) + cheat + description:Invincibility + code:EYNZVYEI + cheat + description:Infinite health + code:SZKEOESE + cheat + description:Infinite lives + code:AANAUAPA + cheat + description:Full health from hearts + code:AAEAUGLA + cheat + description:Less health from hearts + code:ZENANLIA + cheat + description:More health from hearts + code:ZENANLIE + cheat + description:Mega-jump (don't hold jump down too long or you might get stuck) + code:GXEZYVVV + cheat + description:Infinite chances in sub-game (press Start to re-enter the main game) + code:GZSEIYVG + cheat + description:Infinite health (alt) + code:043F:19 + cheat + description:Infinite Chips + code:0117:63 + cheat + description:Infinite lives (alt) + code:043E:09 + +cartridge sha256:f85a689b4ff7a5e51703e5fabc73ca1af43e6519754c4a59c11a960baa323b47 + title:Kid Kool and the Quest for the Seven Wonder Herbs (USA) + cheat + description:Invincibility + code:SEVILPSZ + cheat + description:Infinite time + code:VZOEOGVT + cheat + description:Infinite lives + code:SZKKXIVG + cheat + description:Press Start to complete the level + code:GEXGUALU+LEXGSALU+OXXGXAIK + cheat + description:One life after continue + code:PASKOILA + cheat + description:Start with one life + code:PAVGIALA + cheat + description:Start with double lives + code:TAVGIALA + cheat + description:Start with triple lives + code:PAVGIALE + cheat + description:Invincibility (alt) + code:0031:09 + cheat + description:Infinite lives (alt) + code:0015:09 + +cartridge sha256:81a77623adf819f10548052075555998c1ec1ef5f4dc4bf6ff6b6c3fa3541c1b + title:Kid Niki - Radical Ninja (USA) (Rev A) + cheat + description:Invincibility (glitchy) + code:SZEESTSA+SXVEUISA + cheat + description:Infinite lives + code:GXSOKIVG + cheat + description:Infinite time + code:AESUEGPA + cheat + description:Less time + code:GAUELZTA+GEEPOTTA + cheat + description:Higher jump + code:NYUEXOEV + cheat + description:Multi-jump + code:KTEYSNNN+NNOOKXOE+OAENXNNN+OZEYKNNN+PPEYNNNN+SAEYVNNY+YIEYONNY+AANOVZAP+AEEPKXZA+AEOOUXIZ+APEYXNNY+ATENUNNY+AZENENNY+GAEYUNNY+GZEYENNY+IZENONNN + cheat + description:Start with 1 life + code:PAOATZLA + cheat + description:Start with 6 lives + code:TAOATZLA + cheat + description:Start on round 2 + code:PEVAYPAA+PEUETPAA + cheat + description:Start on round 3 + code:ZEVAYPAA+ZEUETPAA + cheat + description:Start on round 4 + code:LEVAYPAA+LEUETPAA + cheat + description:Start on round 5 + code:GEVAYPAA+GEUETPAA + cheat + description:Start on round 6 + code:IEVAYPAA+IEUETPAA + cheat + description:Invincibility (glitchy) (alt) + code:0088:00+00F4:00 + cheat + description:Infinite lives + code:00CC:03 + cheat + description:Infinite time + code:0621:3B + +cartridge sha256:81e527e9c282f5078a3d08470ad3c032fea9a72f1559ee9d2702ea6b07fab45c + title:Kid Niki - Radical Ninja (USA) + cheat + description:Invincibility + code:EEKEPPAA + cheat + description:Multi-jump + code:LPENONNN+NYNPUXOE+OAENXNNN+OZEYKNNN+PPEYNNNN+SAEYVNNY+YIEYONNY+AANPXXLP+APEYXNNY+ATENUNNY+AZENENNY+GAEYUNNY+GZEYENNY+GZSOXZEY+GZSPKZEY+KTEYSNNN + cheat + description:Invincibility (glitchy) + code:0088:00+00F4:00 + cheat + description:Infinite lives + code:00CC:03 + cheat + description:Infinite time + code:0621:3B + +cartridge sha256:a8f2987d83253adb573aa760c1bb926e951f2c2d72daff4e2d2e125ec1a181c4 + title:King Kong 2 - Ikari no Megaton Punch (Japan) + cheat + description:Infinite health and lives + code:SLSYTPSP + cheat + description:Infinite Rocks + code:SZVEPSSE + cheat + description:Start with max health + code:PESVAAPE+OOSTYAAE + cheat + description:Start with 9 lives + code:PAXVOPZE + +cartridge sha256:6cc3a973288a4c3c96a967bdf1be74eee909d3f5eb16ce0b405f20ce565c66cc + title:King Neptune's Adventure (USA) (Unl) + cheat + description:Infinite health + code:SXXSTVVK+SXUILKVK+SZNIIVSE + cheat + description:Infinite lives + code:SZSKVVVK + cheat + description:Infinite Bubble Bombs + code:SXXYSPVG + cheat + description:Start with all treasures (removes all items from level) + code:AEUGLKEY + cheat + description:Start with 99 Bubble Bombs and Money + code:LVUKGGAA + cheat + description:Start with 99 Seahorses and Keys + code:LTUKSIAA + +cartridge sha256:3249d267ca17098077bb94eee437f354066971bc03c0d06eada05efd92b0fa52 + title:King of Kings, The (USA) (v5.0) (Unl) + cheat + description:Infinite health + code:0512:06 + +cartridge sha256:dc6859332ca69a8361bb3eb8ba1ff638f4bbbc7837a3a9f8a474e05f6bc379ea + title:King of Kings, The (USA) (v1.3) (Unl) + cheat + description:Infinite health + code:0512:06 + +cartridge sha256:9ae715b6f2400d21f5d1ec426ecf310aa68ca46f3b37b37d5ae115f34049676b + title:King of Kings, The (USA) (v1.2) (Unl) + cheat + description:Infinite health + code:0512:06 + +cartridge sha256:d1002d407b544d70b4ddf4515665f6e18ac9c8ee2efd4be184e5240119fd6f70 + title:King of Kings, The (USA) (v1.1) (Unl) + cheat + description:Infinite health + code:0512:06 + +cartridge sha256:be97bca71e1bf099ef0f6ff91aed506df7b0506433c76e5deccea7b130e3a20f + title:King's Knight (USA) + cheat + description:Infinite health + code:GZVXTPSA + cheat + description:Only lose 1 HP when hit + code:OTVXAPSV+PAVXPPAP + cheat + description:Start with double usual health + code:AOSUAOGE + cheat + description:Start with half usual health + code:TESUAOGA + cheat + description:Start with a better character + code:PESUTPAA + cheat + description:Start with the best character normally possible + code:ZESUTPAA + cheat + description:Start with a super character, better than normally Possible + code:IESUTPAA + cheat + description:Infinite health (alt) + code:009A:0C + +cartridge sha256:1250a80faf865aa5ee5585ad7639e5ef2b3fa541554effda5fad2cc5dc2acef5 + title:Kirby's Adventure (USA) (Rev A) + cheat + description:Invincibility + code:EINELGEY + cheat + description:Infinite health + code:SZEPSVSE + cheat + description:Infinite lives + code:SXKTPKVG + cheat + description:Less health from 'pep drinks' + code:ZAKLLXAA + cheat + description:More health from 'pep drinks' + code:APKLLXAA + cheat + description:Full health from 'pep drinks' + code:YZKLLXAE + cheat + description:Start with less health + code:YONZZNYX + cheat + description:Start with more health + code:YKNZZNYX + cheat + description:Start with 2 lives + code:PEVXIYGA + cheat + description:Start with 9 lives + code:AEVXIYGE + cheat + description:Start with 17 lives + code:AOVXIYGA + cheat + description:Invincibility (alt) + code:05F9:02 + cheat + description:Infinite health (alt) + code:0597:2F + cheat + description:Infinite lives (alt) + code:0599:09 + +cartridge sha256:a6b81fec11c24a33fd763db5c28005e760a1614e70c1bb5ccde0bd4242431000 + title:Kirby's Adventure (USA) + cheat + description:Invincibility + code:EINELGEY + cheat + description:Infinite health + code:SZEPSVSE + cheat + description:Infinite lives + code:SXKTPKVG + cheat + description:Less health from 'pep drinks' + code:ZAKLLXAA + cheat + description:More health from 'pep drinks' + code:APKLLXAA + cheat + description:Full health from 'pep drinks' + code:YZKLLXAE + cheat + description:Start with less health + code:YONZZNYX + cheat + description:Start with more health + code:YKNZZNYX + cheat + description:Start with 2 lives + code:PEVXIYGA + cheat + description:Start with 9 lives + code:AEVXIYGE + cheat + description:Start with 17 lives + code:AOVXIYGA + cheat + description:Invincibility (alt) + code:05F9:02 + cheat + description:Infinite health (alt) + code:0597:2F + cheat + description:Infinite lives (alt) + code:0599:09 + +cartridge sha256:9caa01a2b81ce1f98b17520aee09d415da7192382c1e47316998b6c1be6168eb + title:Kiwi Kraze - A Bird-Brained Adventure! (USA) + cheat + description:Invincibility + code:EIUKGIEY + cheat + description:Super-jump + code:XYKTISKN + cheat + description:Infinite lives + code:SUSKLYVI + cheat + description:Infinite continues + code:GZEKXPVS + cheat + description:1 life after continue + code:AAEGNPZA + cheat + description:6 lives after continue + code:IAEGNPZA + cheat + description:9 lives after continue + code:AAEGNPZE + cheat + description:Start with 1 life (and 1 continue) + code:AANGLLZA + cheat + description:Start with 6 lives (and 6 continues) + code:IANGLLZA + cheat + description:Start with 9 lives (and 9 continues) + code:AANGLLZE + cheat + description:Start on level 2 + code:GZVKAUSE+GAVGYLAA + cheat + description:Start on level 3 + code:GZVKAUSE+AAVGYLAE + cheat + description:Start on level 4 + code:GZVKAUSE+GAVGYLAE + cheat + description:Start on level 5 + code:GZVKAUSE+PPVGYLAA + +cartridge sha256:ef63df6bcbc7e13dace53f106a247485a09409799b99c8415e934ba532cdaa53 + title:KlashBall (USA) + cheat + description:Very little team stamina - select the middle team + code:IAUUOOAZ + cheat + description:More team stamina - select the middle team + code:AGUUOOAZ + cheat + description:Mega team stamina - select the middle team + code:OPUUOOAX + cheat + description:Power is doubled for the whole team - select the middle team + code:GAUUKPZA + cheat + description:Power is tripled for the whole team - select the middle team + code:TAUUKPZA + cheat + description:Mega power for the whole team - select the middle team + code:PAUUKPZE + cheat + description:Never lose stamina - select the middle team + code:GXEZAVSO + cheat + description:Computer can't score - select the middle team + code:SZSEZGVT + cheat + description:Everyone including computer has 255 skill - select the middle team + code:GZSXTEAU+GZSXTESN + +cartridge sha256:28b3f1dde1488dd83422da47300d2e31ffce811bf2be37bf6d510019c2289f40 + title:Klax (USA) (Unl) + cheat + description:Infinite drops + code:SXXLUGVT + cheat + description:When starting on level 6, 0 drops allowed + code:PANENGGA + cheat + description:When starting on level 6, 5 drops allowed + code:IANENGGA + cheat + description:When starting on level 11, 0 drops allowed + code:PEOAXGIA + cheat + description:When starting on level 11, 3 drops allowed + code:LEOAXGIA + cheat + description:Start with 0 drops allowed + code:PAVESGLA + cheat + description:Start with 5 drops allowed + code:IAVESGLA + +cartridge sha256:b66538543d3c4c74448e896130081c39112b14898beffbe95137a410394e5dc9 + title:Knight Rider (USA) + cheat + description:Infinite shield + code:SZXSYTSA + cheat + description:Infinite missiles + code:SZEXUNVK + cheat + description:Infinite laser + code:GXXZSVVK + cheat + description:Infinite lives + code:SXXEGEVK+SXKEIEVK + cheat + description:Start with 1 life after continue + code:AEVALAZA + cheat + description:Start with 6 lives after continue + code:IEVALAZA + cheat + description:Start with 9 lives after continue + code:AEVALAZE + cheat + description:Start with 1 life + code:AANKOAZA+VTNKSESE + cheat + description:Start with 6 lives + code:IANKOAZA+VTNKSESE + cheat + description:Start with 99 missiles + code:SZKZYOSU+LYKXAOTT + cheat + description:Start with 99 lasers + code:SZSZLOSU+PYSZGPGN + cheat + description:Start with full gasoline + code:SZUZAOSU+ATUZPPTV + cheat + description:Start with full shield + code:SZUXGOSU+ITUXIOZV + +cartridge sha256:e5673075301b0c84137d24aff0ffbfa0565d33c960968d9843d7bc57f1107417 + title:Krion Conquest, The (USA) + cheat + description:Infinite health + code:SXNIVLSA + cheat + description:Infinite lives + code:SXVLOIVG + cheat + description:Float spell + code:AEOKYTTP + cheat + description:Quicker supershot + code:PEVGOIGA + cheat + description:Less energy used for fire spell + code:GEXYLEAA+IEOYTEPA + cheat + description:Start with 1 life + code:AAKAAPZA + cheat + description:Start with 6 lives + code:IAKAAPZA + cheat + description:Start with 9 lives + code:AAKAAPZE + cheat + description:Start on stage 2 + code:PAXEZPAA+EZXEPOOZ+KAXEIPSA + cheat + description:Start on stage 3 + code:ZAXEZPAA+EZXEPOOZ+KAXEIPSA + cheat + description:Start on stage 4 + code:LAXEZPAA+EZXEPOOZ+KAXEIPSA + cheat + description:Invincibility + code:03DE:02+03E0:3A + cheat + description:Infinite health (alt) + code:004C:28 + cheat + description:Infinite lives (alt) + code:0043:02 + cheat + description:Infinite oxygen in underwater stage + code:0318:05 + cheat + description:Moon-jump (disable in underwater stage) + code:0057:1F + +cartridge sha256:5f981ab1988614a96fd029c6fe3f103465dbf3219265bd8274bf8cd537adee34 + title:Krusty's Fun House (USA) + cheat + description:Infinite health + code:AAUXAEZA + cheat + description:Infinite pies - first life only + code:GXKZPKVK + cheat + description:Pick-up Super Balls instead of Custard Pies + code:AEOXSLPA + cheat + description:Start with 1 life + code:PAKATALA + cheat + description:Start with 6 lives + code:TAKATALA + cheat + description:Start with 9 lives + code:PAKATALE + cheat + description:Start with 6 pies + code:TAKELEPA + cheat + description:Start with 18 pies + code:ZPKELEPA + +cartridge sha256:0ba5e69962f6576d3729aa967092a7e8c98d00213cd98026dee343bff67b4177 + title:Kung Fu (Japan, USA) + cheat + description:Infinite health + code:AUVZEGTA+VEVZOKSX + cheat + description:Infinite time + code:SZUAOAAX + cheat + description:Infinite lives - both players + code:SUAAXA + cheat + description:Invincibility against knives + code:GXSLVYEI + cheat + description:Don't die when time runs out + code:GZVKIYSA+ATVKYNGG + cheat + description:Hit anywhere + code:AASGYXOG + cheat + description:Enemies die when trying to grab you + code:GXKZTIEI+KVKXPSIK+SXKXZIVZ+AVOZLNGG + cheat + description:Enemies easier to shrug off + code:AEVXLSPT + cheat + description:Enemies harder to shrug off + code:ZEVXPIGE + cheat + description:Give P2 an advantage + code:SEZEGG + cheat + description:Knife thrower harder to beat + code:XYUXEUZK + cheat + description:Normal enemies do more damage + code:LEEXSYPA + cheat + description:Walk 2X faster + code:VYNONUNN+ZANOVLPA + cheat + description:Walk 4X faster + code:GANOVLPA+KYNONUNN + cheat + description:Start at last level reached - P1 + code:GZLATG + cheat + description:Start at last level reached - P2 + code:GZLEPG + cheat + description:Start with 1 life - both players + code:PEZELG + cheat + description:Start with 9 lives - both players + code:PEZELK + cheat + description:Infinite health (disable at end of level) + code:04A6:1E + cheat + description:Infinite lives (alt) + code:005C:09 + cheat + description:Knife Thrower doesn't throw knives + code:03E8:00+03E9:00+03EA:00+03EB:00 + cheat + description:Max score + code:0536:09+0535:09+0534:09+0533:09+0532:09+0531:09 + cheat + description:Start on floor 2 + code:005F:01 + cheat + description:Start on floor 3 + code:005F:02 + cheat + description:Start on floor 4 + code:005F:03 + cheat + description:Start on floor 5 + code:005F:04 + +cartridge sha256:323d330cb50e0a4cd7855a3eedb0e97a08b31d9f7c638e4fa53ab58c1263154e + title:Kung-Fu Heroes (USA) + cheat + description:Infinite lives + code:AESLZLPA + cheat + description:Infinite Miracle Kicks + code:AEVSPAPA + cheat + description:2 E-balls for an extra life + code:ZAXUEGIA + cheat + description:Use with warp to start with 1 life + code:PASZNPLA + cheat + description:Use with warp to start with 6 lives + code:TASZNPLA + cheat + description:Use with warp to start with 9 lives + code:PASZNPLE + cheat + description:Mega-jumps left and right + code:GAOKOGPA+KYXGOKNN + cheat + description:Start with 20 Miracle Kicks + code:GPVZXPAA + cheat + description:Start with 1 life + code:PASXSPIA + cheat + description:Start with 9 lives + code:PASXSPIE + cheat + description:Start on Castle 2 + code:OZSZXPSX+GASZUOSG + cheat + description:Start on Castle 3 + code:OZSZXPSX+AASZUOSK + cheat + description:Start on Castle 4 + code:OZSZXPSX+GASZUOSK + cheat + description:Start on Castle 5 + code:OZSZXPSX+APSZUOSG + cheat + description:Start on Castle 6 + code:OZSZXPSX+GPSZUOSG + cheat + description:Start on Castle 7 + code:OZSZXPSX+APSZUOSK + cheat + description:Start on Castle 8 + code:OZSZXPSX+GPSZUOSK + +cartridge sha256:f4b7d8d31c5bbfee69c117332fa3878d04dc3b6e693d1a343d3ef2f20b10a85e + title:Last Action Hero (USA) + cheat + description:Infinite health + code:SXOLSGTG + cheat + description:One hit kills on bosses + code:ESXZLAEY + cheat + description:Infinite lives + code:SXXLOGVG + cheat + description:Infinite continues + code:SZEVZIVG + cheat + description:Red hearts worth nothing + code:VZSAEYVT + cheat + description:Continue with 1 life + code:AASTAILA + cheat + description:Continue with 2 lives + code:PASTAILA + cheat + description:Continue with 3 lives + code:ZASTAILA + cheat + description:Start with 1 life + code:AAUVSTLA + cheat + description:Start with 7 lives + code:TAUVSTLA + cheat + description:Start with 10 lives + code:PAUVSTLE + cheat + description:Start with 0 continues + code:AAKTOTZA + cheat + description:Start with 5 continues + code:IAKTOTZA + cheat + description:Start with 9 continues + code:PAKTOTZE + cheat + description:Start on stage 2 - Hamlet + code:ZENTAAAA + cheat + description:Start on stage 3 - The House + code:GENTAAAA + cheat + description:Start on stage 4 - The Freeway + code:IENTAAAA + cheat + description:Start on stage 5 - The Office block + code:TENTAAAA + cheat + description:Start on stage 6 - The Helicopter + code:YENTAAAA + cheat + description:Start on stage 7 - The Film Premiere + code:AENTAAAE + cheat + description:Start on Stage 8 - The Cinema + code:PENTAAAE + cheat + description:Start on the end-of-level bad guy + code:ZENTAAAE + cheat + description:Invincibility (blinking) + code:008C:19 + cheat + description:Infinite health (alt) + code:002E:2F + cheat + description:Infinite lives (alt) + code:0092:09 + +cartridge sha256:f15382be46e474c596566c5a726ae39dadfa18289722bac2da44b6493bbabfec + title:Last Ninja, The (USA) + cheat + description:Infinite health + code:SXSEEZSA + cheat + description:Press Select on controller 2 to skip to next level, A for next screen, B for previous screen + code:EYETYIEI + cheat + description:Infinite lives + code:007D:09 + cheat + description:Infinite time (seconds) + code:0369:00 + +cartridge sha256:54dd62754f48e39af39c3e8d645897af25aaba31523267bc41d4c95f2b0348d5 + title:Last Starfighter, The (USA) + cheat + description:Infinite lives - both players + code:SZVPATVG + cheat + description:Stop irritating shake + code:GXUPLGSA + cheat + description:Start with 1 life - both players + code:PANENLIA + cheat + description:Start with 6 lives - both players + code:TANENLIA + cheat + description:Start with 9 lives - both players + code:PANENLIE + cheat + description:Start with 1 life - P2 + code:KEEAVLSA + cheat + description:Start on level 5 - P1 + code:GAVEKLAA+GZVENLSA+GZNAOLSA + cheat + description:Start on level 10 - P1 + code:PAVEKLAE+GZVENLSA+GZNAOLSA + cheat + description:Start on level 14 - P1 + code:IAVEKLAE+GZVENLSA+GZNAOLSA + +cartridge sha256:53923dcb59afac40fbfed4aa2298be156b5b9763ec43956757ec44092ba799c5 + title:Layla (Japan) + cheat + description:Infinite energy + code:SXSTTPVG + cheat + description:Infinite Machine Gun ammo + code:SXVIPGVG + cheat + description:Infinite Dynamite Sticks + code:SXVSPIVG + cheat + description:Infinite Grenades + code:SZOSYIVG + +cartridge sha256:203dc9486ba58e65f9a4289da476dc15ff34d6fd39d355b438ae4db2d182746d + title:Legacy of the Wizard (USA) + cheat + description:Infinitel ife + code:GXVTZYSA + cheat + description:Infinite magic + code:GXNTYYVG + cheat + description:Never lose items + code:GXSVLGVI + cheat + description:Shopkeeper forgets to charge + code:GZKVUASA + cheat + description:No enemies + code:OUOVNPOP + cheat + description:Walk through walls + code:GKPSOS + cheat + description:Lyll's strength tripled + code:LEUYKYPA + cheat + description:Lyll's jumping improved + code:AUUYUNZP + cheat + description:Roas' strength tripled + code:LEUYEYPA + cheat + description:Roas' jumping improved + code:ZXXNNYGO + cheat + description:Xemn's strength tripled + code:PEXNEYLE + cheat + description:Xemn's jumping improved + code:AXXYNYZP + cheat + description:Menya's strength tripled + code:TEXNKYZA + cheat + description:Menya's jumping improved + code:AXXNUYGP + +cartridge sha256:d2a585ff6febf59447f9bd9fbb387ae4985385d6f6f61a70e145a5ee69523018 + title:Legendary Wings (USA) + cheat + description:Almost infinite health + code:AAEEGLPA+AEEATIPA + cheat + description:Gain double powers on pick-up + code:ZANAIZPA+ZEVAPIPA + cheat + description:Gain triple powers on pick-up + code:LANAIZPA+ZEVAPZPA + cheat + description:Start with 1 life - P1 + code:PEEALYLA + cheat + description:Start with 6 lives - P1 + code:TEEALYLA + cheat + description:Start with 9 lives - P1 + code:PEEALYLE + cheat + description:Start with 1 life - both players + code:PANEAYLA + cheat + description:Start with 6 lives - both players + code:TANEAYLA + cheat + description:Start with 9 lives - both players + code:PANEAYLE + cheat + description:Infinite health - P1 + code:0520:63 + cheat + description:Infinite lives - P1 + code:0058:09 + cheat + description:Have Double shot + code:007A:01 + cheat + description:Have Rapid Fire shot + code:007A:02 + cheat + description:Have Crazy Ball shot + code:007A:03 + cheat + description:Have Firebird ability + code:007A:04 + cheat + description:One hit kills on bosses + code:04B0:00 + +cartridge sha256:3b5627bc1ebaa7a84953d7337c7684a93beaf973f4a8b3a42b513dc1e0ab0a09 + title:Legends of the Diamond - The Baseball Championship Game (USA) + cheat + description:1 ball and you walk + code:PEKLAIGA + cheat + description:2 balls and you walk + code:ZEKLAIGA + cheat + description:6 balls to walk + code:TEKLAIGA + cheat + description:1 strike and you're out (fouls don't count as strikes) + code:PASUGILA + cheat + description:2 strikes and you're out (fouls don't count as strikes) + code:ZASUGILA + cheat + description:5 strikes and you're out (fouls don't count as strikes) + code:IASUGILA + +cartridge sha256:9d83796d8feba9713fa5a1354fd9253cda5cb33ab5bc6f1c6f97d5eb90aef6c3 + title:Legend of Kage, The (USA) + cheat + description:Invincibility + code:SZNPVLSA + cheat + description:Infinite lives - both players + code:SXVALZVG + cheat + description:Hit anywhere with Shurikens + code:AESXNKZA+AESZUGTP+AEXXNKLT + cheat + description:Hit anywhere with Sword + code:AAEZVIGP+AAOZXSAA+AEXXNKLT + cheat + description:Kill the white boss (you do not need to kill the butterfly) + code:AEXXNKLT + cheat + description:Super-ninja-power running ability + code:GASAOLZA + cheat + description:Super-ninja-power jumping ability + code:YAKXYPGE+YASZAPGE+YASZPPGE + cheat + description:Start with 28 lives - both players + code:KEOATAVA + cheat + description:Infinite lives - P1 + code:002B:63 + +cartridge sha256:1849bb687d038a43971651b13392481768ea0bc15f3d04b6898f052bbfa356e5 + title:Legend of the Ghost Lion (USA) + cheat + description:Infinite Courage points + code:SZUPNNSE + cheat + description:Infinite Dream points + code:SXXKTSSE + cheat + description:Buy items for free in most shops (must have enough rubies to purchase item) + code:SXSKLKSE + cheat + description:Infinite health - main character + code:04A1:FF + cheat + description:Max Dream - main character + code:04A3:FF+04A4:FF + cheat + description:Max Dream total - main character + code:04A5:FF + cheat + description:Max Hope - main character + code:04A0:FF + cheat + description:Max Rubies + code:041A:FF + cheat + description:Have #2 Whip + code:0562:2A + cheat + description:Have F-Sword + code:0562:2B + +cartridge sha256:ec0d4ebf6d2fcecd1d95fef7329954efe79676959bc281ea908b226459bc6dc2 + title:Legend of Zelda, The (USA) (Rev A) + cheat + description:Infinite health + code:AVVLAUSZ + cheat + description:Have the Pink Ring (infinite health) + code:ZTSPSTIP + cheat + description:Infinite Bombs + code:SZNZVOVK + cheat + description:Have Blue Ring effect + code:ESKUILTA + cheat + description:Have Red Ring effect + code:OSKUILTA + cheat + description:All items are free + code:SZVXASVK+AEVEVALG + cheat + description:Fewer enemies + code:AEOANAEG + cheat + description:No dark rooms + code:AOEUYTEY + cheat + description:No Zolas + code:AEVATVAA + cheat + description:Reset counter to zero + code:PALZZI + cheat + description:Speed writing + code:OPPEEA + cheat + description:Walk faster + code:OXELYLSX+EUEUALAA + cheat + description:Walk through walls in dungeons + code:SXXOPPSA+ATKOLPEY + cheat + description:Create character with 8 life hearts + code:YYKPOYZZ + cheat + description:Create character with 16 life hearts + code:NYKPOYZX + cheat + description:Invincibility + code:7AA7:60 + cheat + description:Invincibility (blinking) + code:04F0:09 + cheat + description:Infinite health (alt) + code:0670:FF + cheat + description:Hit anywhere + code:7BF2:24+7C28:AD + cheat + description:Get items from anywhere + code:7353:24+735F:24 + cheat + description:Infinite Bombs (alt) + code:0658:FF + cheat + description:Infinite Keys + code:066E:03 + cheat + description:Infinite Rupies + code:066D:FF + cheat + description:Enemies don't shoot anything + code:034C:FF + cheat + description:Turbo Sword + code:03DD:01 + cheat + description:Have all Tri-Force pieces + code:0671:FF + cheat + description:Have Maps for Dungeons 1-8 and Compass for Dungeon 9 + code:0668:FF+0669:FF + cheat + description:Have Map for Dungeon 9 + code:066A:FF + cheat + description:Have Arrows + code:0659:01 + cheat + description:Have Blue Candle + code:065B:01 + cheat + description:Have Bow + code:065A:01 + cheat + description:Have Enemy Bait + code:065D:01 + cheat + description:Have Flute + code:065C:01 + cheat + description:Have Ladder + code:0663:01 + cheat + description:Have Magic Book + code:0661:01 + cheat + description:Have Magic Boomerang + code:0675:01 + cheat + description:Have Magic Wand + code:065F:01 + cheat + description:Have Magical Key + code:0664:01 + cheat + description:Have Magical Shield + code:0676:01 + cheat + description:Have Magical Sword + code:0657:03 + cheat + description:Have Power Bracelet + code:0665:01 + cheat + description:Have Raft + code:0660:01 + cheat + description:Have Red Candle + code:065B:02 + cheat + description:Have Silver Arrows + code:0659:02 + cheat + description:Have White Sword + code:0657:02 + cheat + description:Have Wooden Sword + code:0657:01 + +cartridge sha256:085e5397a3487357c263dfa159fb0fe20a5f3ea8ef82d7af6a7e848d3b9364e8 + title:Legend of Zelda, The (USA) + cheat + description:Infinite health + code:AVVLAUSZ + cheat + description:Have the Pink Ring (infinite health) + code:ZTSOOTIP + cheat + description:Infinite Bombs + code:SZNZVOVK + cheat + description:All items are free + code:SZVXASVK+AEVEVALG + cheat + description:Almost no enemies in Overworld + code:AAXPILGA+AAXPTLIA+AAXPYLTA + cheat + description:Fewer enemies + code:AEOANAEG + cheat + description:No dark rooms + code:AOEUYTEY + cheat + description:No Zolas + code:AEVATVAA + cheat + description:Reset counter to zero + code:PALZZI + cheat + description:Speed writing + code:OPPEEA + cheat + description:Walk faster + code:OXELYLSX+EUEUALAA + cheat + description:Walk through walls in dungeons + code:SXOOYPSA+ATKPPPEY + cheat + description:Create character with 8 life hearts + code:YYKPOYZZ + cheat + description:Create character with 16 life hearts + code:NYKPOYZX + cheat + description:Invincibility + code:7AA7:60 + cheat + description:Invincibility (blinking) + code:04F0:09 + cheat + description:Infinite health (alt) + code:0670:FF + cheat + description:Hit anywhere + code:7BF2:24+7C28:AD + cheat + description:Get items from anywhere + code:7353:24+735F:24 + cheat + description:Infinite Bombs (alt) + code:0658:FF + cheat + description:Infinite Keys + code:066E:03 + cheat + description:Infinite Rupies + code:066D:FF + cheat + description:Enemies don't shoot anything + code:034C:FF + cheat + description:Turbo Sword + code:03DD:01 + cheat + description:Have all Tri-Force pieces + code:0671:FF + cheat + description:Have Maps for Dungeons 1-8 and Compass for Dungeon 9 + code:0668:FF+0669:FF + cheat + description:Have Map for Dungeon 9 + code:066A:FF + cheat + description:Have Arrows + code:0659:01 + cheat + description:Have Blue Candle + code:065B:01 + cheat + description:Have Bow + code:065A:01 + cheat + description:Have Enemy Bait + code:065D:01 + cheat + description:Have Flute + code:065C:01 + cheat + description:Have Ladder + code:0663:01 + cheat + description:Have Magic Book + code:0661:01 + cheat + description:Have Magic Boomerang + code:0675:01 + cheat + description:Have Magic Wand + code:065F:01 + cheat + description:Have Magical Key + code:0664:01 + cheat + description:Have Magical Shield + code:0676:01 + cheat + description:Have Magical Sword + code:0657:03 + cheat + description:Have Power Bracelet + code:0665:01 + cheat + description:Have Raft + code:0660:01 + cheat + description:Have Red Candle + code:065B:02 + cheat + description:Have Silver Arrows + code:0659:02 + cheat + description:Have White Sword + code:0657:02 + cheat + description:Have Wooden Sword + code:0657:01 + +cartridge sha256:494aa7d49d3f4d66f01cac0f31a9bc7bc9626faa575a635f43e7caf19a832a48 + title:Lemmings (USA) + cheat + description:Infinite time + code:SXUTLAVG + cheat + description:Infinite climbers + code:SZVVTPVG + cheat + description:Infinite floaters + code:SXOVAPVG + cheat + description:Infinite bombers + code:SXKTYPVG + cheat + description:Infinite blockers + code:SZOTPZVG + cheat + description:Infinite builders + code:SZVTPZVG + cheat + description:Infinite bashers + code:SXXVLZVG + cheat + description:Infinite miners + code:SZETGLVG + cheat + description:Infinite diggers + code:SZSTYLVG + +cartridge sha256:97c67809c952bc25060a01dca224eedc5ed76cc770bac44452c92cd3a1d4a418 + title:Lethal Weapon (USA) + cheat + description:Infinite ammo when shooting on the ground + code:OLSSGSOO + cheat + description:Infinite ammo when shooting in the air + code:OUSSISOO+OUXIPSOO + cheat + description:E restores health completely + code:AKVIXAAP + cheat + description:E worth nothing + code:AEVIXAAP + cheat + description:Extra ammo restores ammo completely + code:AKKSEAAP + cheat + description:Extra ammo worth nothing (if you run out of ammo you can't use gun till next stage) + code:AEKSEAAP + cheat + description:No health lost when falling off screen + code:AEUYXAAZ + cheat + description:Falling off screen is fatal + code:AKUYXAAZ + cheat + description:Bullet proof vest lasts longer + code:NNNISAAU + cheat + description:Bullet proof vest lasts until end of stage, except when you die from punches or falling off screen + code:XVUKOOXK + cheat + description:Bullet proof vest does not last as long + code:ZENISAAU:or:AONISAAL + cheat + description:Start on Level 2 + code:XTUGTXXK + cheat + description:Start on Level 3 + code:XZUGLXVL+LAUGGZNP+XTUGIZEK + cheat + description:Invincibility (blinking) - P1 + code:05ED:09 + cheat + description:Infinite health + code:05C0:3F + cheat + description:Infinite ammo + code:003F:3A + cheat + description:One hit kills on bosses + code:05C4:00 + +cartridge sha256:dbd530e6ca07cc4b255b1b885cd5b6b2e23b8d3cac4733c3e4d96acd7d751c28 + title:Life Force (USA) + cheat + description:Infinite lives + code:GZKGILVI + cheat + description:Keep pods after death + code:GZSGLTSP + cheat + description:Hit anywhere + code:AAUIPXTP+AAUSTXIA+ATNILXOZ+EIKSZZEP + cheat + description:One hit kills most enemies + code:OXOSPXOV + cheat + description:Press Start to finish the level + code:TKOYVIGX+ZEOYKIPA + cheat + description:Start with Speed + code:PEKGPTAA + cheat + description:Start with Missile + code:ZEKGPTAA + cheat + description:Start with Ripple + code:LEKGPTAA + cheat + description:Start with Laser + code:GEKGPTAA + cheat + description:Start with Option + code:IEKGPTAA + cheat + description:Start with Force Field + code:TEKGPTAA + cheat + description:Start at the volcanic stage + code:PEUTSTAA + cheat + description:Start at the prominence stage + code:ZEUTSTAA + cheat + description:Start at cell stage 2 + code:LEUTSTAA + cheat + description:Start at the temple stage + code:GEUTSTAA + cheat + description:Start at the mechanical city stage + code:IEUTSTAA + cheat + description:Start with 1 life + code:PEKVNTLA + cheat + description:Start with 6 lives + code:TEKVNTLA + cheat + description:Invincibility - P1 + code:0084:C0 + cheat + description:Invincibility - P2 + code:0085:C0 + cheat + description:Infinite lives (alt) + code:0034:63 + cheat + description:Complete the level + code:004E:02 + cheat + description:Progress through the level faster + code:003A:02 + cheat + description:Have 30 lives option + code:07EF:01 + cheat + description:Have upgraded Laser + code:0076:03 + cheat + description:Have double Speed + code:0080:02 + cheat + description:Have triple Speed + code:0080:03 + cheat + description:Have Shield + code:0082:09 + cheat + description:Have double Missile + code:0086:02 + cheat + description:Have Option + code:0091:01 + +cartridge sha256:36769f543b6cfb08c5ef8673a11a7b27264bdd60323a62e9083b3da47eb33a8c + title:Lightgun Game 2 in 1 - Cosmocop + Cyber Monster (Asia) (Unl) + cheat + description:Cosmo Cop - Infinite lives + code:SXXKNUVK + cheat + description:Cosmo Cop - Infinite ammo + code:SZXGXUSE + cheat + description:Cosmo Cop - Infinite energy + code:SZVKEUVK+SZVKUUVK + cheat + description:Cyber Monster - Infinite misses + code:ATSPASVG + +cartridge sha256:745164dee8e4af6a7150d21e9ef082f56a51b01c5c32f28cdf4cd211bed3714d + title:Lightgun Game 2 in 1 - Tough Cop + Super Tough Cop (Asia) (Unl) + cheat + description:Infinite health + code:037A:06 + +cartridge sha256:cecc797ffc82c5764e89038262c00b325f44afc0d9fc4b5bef295ea227e1dd22 + title:Lion King, The (Europe) + cheat + description:Invincibility + code:EINEILEY+EIVLYGEY + cheat + description:Infinite lives + code:SXNEAKVK + +cartridge sha256:68e98b1b8dc5da610321f92718b4b4c2b2b71b6c752ff25ca6926e26cd91c57f + title:Little Mermaid, The (USA) + cheat + description:Invincibility + code:ESSGSPEY+ESEELPEY + cheat + description:Invincibility after one hit + code:SXSGNPVG + cheat + description:Infinite lives + code:SZSSPLVG + cheat + description:Keep red pearls after dying + code:GZSILLSA + cheat + description:Keep green pearls after dying + code:GZSIILSA + cheat + description:Get all pearls after dying + code:LASIZLAA + cheat + description:Start with all red pearls + code:LAKKGTAA+ILKKTVOV + cheat + description:Start with all green pearls + code:LAKKGTAA+TLKKTVOV + cheat + description:Start with 1 heart + code:PASGGTLA+PAXGAYLA + cheat + description:Start with 5 hearts + code:IASGGTLA+IAXGAYLA + cheat + description:Start with 1 life + code:AASGATZA + cheat + description:Start with 6 lives + code:IASGATZA + cheat + description:Start with 9 lives + code:AASGATZE + cheat + description:Start on Ursula stage + code:IAKKGTAA + cheat + description:Start on stage 2 + code:PAKKGTAA + cheat + description:Start on stage 3 + code:ZAKKGTAA + cheat + description:Start on stage 4 + code:LAKKGTAA + cheat + description:Start on stage 5 + code:GAKKGTAA + +cartridge sha256:e95d3557fa60bacabe7a0b65277cdf2f084b6f58b55784d3d631ab030def0a91 + title:Little Nemo - The Dream Master (USA) + cheat + description:Infinite life + code:SXKTGEVK + cheat + description:Infinite lives + code:SZOKSLVG + cheat + description:Mega-jump + code:TOKZKNZA + cheat + description:Speed jumps + code:GESLYPPA+UYUUIOVN + cheat + description:Super speed + code:ZEXLLPPA+SYEUPOVN + cheat + description:Start with 1 life + code:PEKKSZLA + cheat + description:Start with 6 lives + code:TEKKSZLA + cheat + description:Start with 9 lives + code:PEKKSZLE + cheat + description:Start on stage 2 + code:PEUKOZAA + cheat + description:Start on stage 3 + code:ZEUKOZAA + cheat + description:Start on stage 4 + code:LEUKOZAA + cheat + description:Start on stage 5 + code:GEUKOZAA + cheat + description:Start on stage 6 + code:IEUKOZAA + cheat + description:Start on stage 7 + code:TEUKOZAA + cheat + description:Start on stage 8 + code:YEUKOZAA + cheat + description:Invincibility (blinking) + code:0630:03 + cheat + description:Infinite life (alt) + code:05D0:05 + cheat + description:Infinite lives (alt) + code:008E:09 + cheat + description:Infinite Keys + code:008C:09 + cheat + description:Fly + code:0540:FF + +cartridge sha256:50badb618accf0ca28966c05ca4ff159aa9afa2fccd7f0354b8eff6af105a8f0 + title:Little Ninja Brothers (USA) + cheat + description:Invincibility + code:AIULZPEI + cheat + description:Invincibility to water + code:SXSZXNTS + cheat + description:Infinite Life + code:OLKUAOOO + cheat + description:Infinite Dragon Kicks + code:AEUUYKIA + cheat + description:Infinite money + code:AVSIOOSZ + cheat + description:Mighty Ball always available + code:AEEOKZPA + cheat + description:T-Star always available + code:ATUOSUSZ + cheat + description:All T-Stars + code:OZXONUPX + cheat + description:Max money after fights + code:AEOSKPZA + cheat + description:Quick level up + code:AAXIVOZP + cheat + description:Start with 255 Life + code:NYUSKXZE + cheat + description:Start with 50 Attack + code:ZLUSSZPA + cheat + description:Have Batteries + code:0449:02 + cheat + description:Have Marks + code:042A:06 + cheat + description:Have Meat Bun + code:044D:01 + cheat + description:Have Medicine + code:044B:01 + cheat + description:Have Prism Claw + code:0439:08 + cheat + description:Have Prism Sword + code:043B:05 + cheat + description:Have Prism Shield + code:043C:04 + cheat + description:Have Sacred Robe + code:043D:04 + cheat + description:Have Sweet Buns + code:044C:08 + cheat + description:Have T-Stars + code:042B:08 + cheat + description:Have Whirly Birds + code:044A:01 + +cartridge sha256:a5165565263eaf8bdc45a8e6a615704f9bf271cd6d547d22c098c80cbaffd879 + title:Little Samson (USA) + cheat + description:Invincibility against enemies + code:APSELZEI + cheat + description:Infinite health + code:GZVEPXSN + cheat + description:Infinite lives + code:GXOVAGVG + cheat + description:Hit anywhere + code:ALUAIGEL + cheat + description:Collectable items never disappear + code:AVKXSXVI + cheat + description:Increase Samson's health gauge + code:AOKTPSAE + cheat + description:Increase Kikira's health gauge + code:AOKTZSAE + cheat + description:Increase Gamm's health gauge + code:AXKTLIAP + cheat + description:Increase K.O.'s health gauge + code:AOKTGIGA + cheat + description:Increase Samson's health + code:AOKTISAE + cheat + description:Increase Kikira's health + code:AOKTTSAE + cheat + description:Increase Gamm's health + code:AXKTYIAP + cheat + description:Increase K.O.'s health + code:AOKVAIGA + cheat + description:Crystal ball adds 4 units to health gauge + code:AAUZEZGE + cheat + description:Small hearts give 4 health units + code:AESXVPZE + cheat + description:Infinite health - Little Samson + code:0097:08 + cheat + description:Infinite health - Dragon + code:0098:08 + cheat + description:Infinite health - Golem + code:0099:0F + cheat + description:Infinite health - Mouse + code:009A:04 + +cartridge sha256:33c362ea3dbce2ac449e0d877d85904c26fcaf4b197e27b23efe9cbe67f20e15 + title:Locksmith (Asia) (PAL) (Unl) + cheat + description:Infinite health + code:0573:23 + cheat + description:Infinite time + code:056A:01 + cheat + description:Instantly beat puzzle + code:0043:FF + +cartridge sha256:6c17c7bf2f7466eb43718305a0d74bd75f31b65429bc1fe406c34565e792310c + title:Lode Runner (USA) + cheat + description:Invincibility + code:GXOKIGEY+GXOGTGEY+GZNGLGEY + cheat + description:Infinite lives + code:GZNGYIVG + cheat + description:Moonwalk + code:APOIGPAL + cheat + description:Heavy gravity + code:GAUGVGYA+AAKGEGGA + cheat + description:Start with 1 life + code:PASKLTIA + cheat + description:Start with 10 lives + code:ZASKLTIE + +cartridge sha256:622ef597b328a204fafcef55c9aef0de08489a43898a6c9adaa9d39971e06f69 + title:Lone Ranger, The (USA) + cheat + description:Infinite health - side views only + code:GZKKYPSA + cheat + description:Infinite regular and silver bullets + code:AASXUAPA + cheat + description:Cheaper silver bullets + code:IEUZTNZA + cheat + description:Cheaper standard bullets + code:ZEUZIYIA + cheat + description:Don't lose money when shooting bystanders + code:GZSZNATG+GZSXOATT + cheat + description:Start with 255 dollars + code:NNKNTIGV + cheat + description:Start with 10 silver bullet rounds + code:ZESYTIIE + cheat + description:Start with 15 silver bullet rounds + code:YESYTIIE + cheat + description:Start with 15 standard bullet rounds + code:YESYZSZE + cheat + description:Start with 30 standard bullet rounds + code:TOSYZSZE + cheat + description:Infinite health + code:005F:0C + cheat + description:Infinite money + code:0050:FF+DF30:FF + cheat + description:Infinite regular and silver bullets (alt) + code:0052:06 + cheat + description:Infinite T.N.T. + code:0055:63 + +cartridge sha256:4fb6c5c8359dcbabcb4d05cf36192c790e68a509ef8666c20ebdb81541df3243 + title:Low G Man - The Low Gravity Man (USA) + cheat + description:Infinite life (blinking) + code:SZEENESE + cheat + description:Infinite vehicle fuel + code:SZVSKOVK + cheat + description:Infinite time + code:GZKINOVK + cheat + description:Infinite lives + code:SZNIEEVK + cheat + description:Full life gained from capsules + code:AAEZATZE + cheat + description:Less life gained from capsules + code:PAEZATZA + cheat + description:Full EMDP on a new life + code:LAVSKAPA + cheat + description:Full AGM on a new life + code:ZAVIKAAA + cheat + description:10 Boomerangs on pick-up + code:ZEOZZTLE + cheat + description:10 Fireballs on pick-up + code:ZAVXGTLE + cheat + description:10 Bombs on pick-up + code:ZEUXATLE + cheat + description:10 Waves on pick-up + code:ZESXTTLE + cheat + description:1 life after continue + code:PEOSKALA + cheat + description:6 lives after continue + code:TEOSKALA + cheat + description:9 lives after continue + code:PEOSKALE + cheat + description:Start with 1 life + code:PEXIZTLA + cheat + description:Start with 6 lives + code:TEXIZTLA + cheat + description:Start with 9 lives + code:PEXIZTLE + cheat + description:Infinite life + code:0639:08 + cheat + description:Infinite lives (alt) + code:06D6:09 + cheat + description:Infinite time (alt) + code:0738:FF + cheat + description:Enemies die instantly + code:050A:00+050E:00 + cheat + description:Jump higher + code:0647:35 + cheat + description:Rank is 03/03 + code:0651:03 + cheat + description:Rank left is 99/99 + code:0656:63+0657:63 + +cartridge sha256:52812b55986f96fa77eb24a76e795dc8d79977eec7488c7b5b84ac3b47d60366 + title:M.C. Kids (USA) + cheat + description:Infinite lives + code:GXKSUOSE + cheat + description:Infinite hearts + code:EGETYTIA + cheat + description:Don't lose Golden Arches when hit + code:EKNVYIIA + cheat + description:Super-jump + code:AOVEGTGE+AEVEPTLA + cheat + description:1 heart per life + code:AAKSAYZA+AEKSNPZA + cheat + description:8 hearts per life + code:YAKSAYZA+YEKSNPZA + cheat + description:Start with 2 lives + code:PAKILYLA + cheat + description:Start with 7 lives + code:TAKILYLA + cheat + description:Start with 10 lives + code:PAKILYLE + +cartridge sha256:345fe1e466b3e8d7a8b7f01f545808793b120ad17ed8497ddc306e205b2589a3 + title:M.U.L.E. (USA) + cheat + description:4 'months' for beginner game + code:GEKALTTA + cheat + description:9 'months' for beginner game + code:PEKALTTE + cheat + description:6 'months' for standard game + code:TEXAIVGA + cheat + description:20 'months' for standard game + code:GOXAIVGA + cheat + description:Humanoids start with $400 + code:EPOEPNAI+PAOETYZA + cheat + description:Humanoids start with $800 + code:AZOEPNAI+LAOETYZA + cheat + description:Flappers start with $1300 + code:GPUAAYAG+IAUAIYTA + cheat + description:Flappers start with $2000 + code:EIUAAYAG+YAUAIYTA + +cartridge sha256:d10e4280b6ca868142061ab731aeb378c983334b89a1727a524c57c241812d13 + title:M.U.S.C.L.E. - Tag Team Match (USA) + cheat + description:Invincibility - P1 team + code:OZUEPZSX+LTUEZXYG + cheat + description:Set bout length timer to 20 + code:ZESELPLA + cheat + description:Set bout length timer to 60 + code:TESELPLA + cheat + description:Set bout length timer to 90 + code:PESELPLE + cheat + description:Computer controlled players jump faster + code:ZEUOUPPA + cheat + description:Computer controlled players speed up + code:ZASXAAPA + +cartridge sha256:80757aa85fe4001123cb839db0fc72fc7e06020ecba5c89abb049b8490fd3d0b + title:Mad Max (USA) + cheat + description:Infinite ammo + code:SXVAEVVK + cheat + description:No damage done to car + code:AENEPYAP + cheat + description:Less damage done to car + code:GENEPYAP + cheat + description:More damage done to car + code:AXNEPYAP + cheat + description:No damage done to you + code:AAUAUEAA + cheat + description:Less damage done to you + code:GAUAUEAA + cheat + description:More damage done to you + code:APUAUEAA + cheat + description:A better tune-up + code:AVKVLPAZ + cheat + description:Dynamite is free + code:AANEPZPA + cheat + description:Ammo is free + code:AAVEGZPA + cheat + description:Cheaper arena pass + code:GEEATZYA+GLKELZYL + cheat + description:Start with full food and water + code:NYEYVYAX + cheat + description:Start with less ammo + code:AGOYUYEA + +cartridge sha256:ab0a43bc7c33f0cdd8acf15c4da967ba2af56431de1a598b9767bd10e78cc8fa + title:Mafat Conspiracy, The (USA) + cheat + description:Infinite bullets + code:GXOGZZVG + cheat + description:Infinite time + code:XTNIVXXK + cheat + description:Immune to physical damage + code:GZNGOTOY + cheat + description:Immune to weapon damage + code:GZOKSSON + cheat + description:Immune to damage in maze + code:GXNGPOSN + cheat + description:Fewer bullets on pick-up + code:IASGUSZA + cheat + description:More bullets on pick-up + code:GPSGUSZA + cheat + description:Faster timer + code:AZNIEXGL + cheat + description:Slower timer + code:AYNIEXGL+AYVISXGL + +cartridge sha256:2eee5b14a90458088ac18c36352ab605ae4fe452a59f2675937acee0d15e94b6 + title:Magic Carpet 1001 (Unl) + cheat + description:Invincibility + code:AVEAYKAL + +cartridge sha256:9a5d7367891f4d929fe5e3be5fe2988e3e6c0b0d70b7cd401976f16b3b5f0a9d + title:Magic Jewelry (Asia) (Unl) + cheat + description:Bypass checksum check + code:GXUTAYEI+GXXVAYEI + cheat + description:Speed never increases + code:AEETNKIT+XXETVGVZ + cheat + description:Disable Game Over + code:GXUVYYEP + +cartridge sha256:caae56599689d4297c3be1afdc77d5bfc510d47d6e668244c308b9732eb41dea + title:Magician (USA) + cheat + description:Start on area 2 - Wilderness + code:0051:01 + cheat + description:Start on area 3 - Lake + code:0051:02 + cheat + description:Start on area 4 - Forest + code:0051:03 + cheat + description:Start on area 5 - Caverns + code:0051:04 + cheat + description:Start on area 6 - Dungeons + code:0051:05 + cheat + description:Start on area 7 - Castle + code:0051:06 + cheat + description:Start on area 8 - Tower + code:0051:07 + cheat + description:Start on the Tower Top boss + code:0051:08 + +cartridge sha256:527faba646cd9e959a4df5d015cd14ac3fae461b06655be99d47c1a754384097 + title:Magic of Scheherazade, The (USA) + cheat + description:Infinite HP + code:OTSXLGSV + cheat + description:Infinite lives + code:SXEVPLVG + cheat + description:Less energy gained from Bread + code:POKAOZZU + cheat + description:Less magic gained from Mashroobs + code:ZAEEXGIA + cheat + description:Never lose Mashroobs + code:SZEAEKVK + cheat + description:Start with only 20 Gold Coins + code:ZAUTAZIA + cheat + description:Start with 1 life + code:PAKTAZLA + cheat + description:Start with 6 lives + code:TAKTAZLA + cheat + description:Start with 9 lives + code:PAKTAZLE + cheat + description:Infinite HP (alt) + code:0081:FF + cheat + description:Infinite MP + code:008D:18 + cheat + description:Infinite Bread + code:0306:25 + cheat + description:Infinite Carpets + code:0311:10 + cheat + description:Infinite Mashroob + code:0307:25 + cheat + description:Infinite R. Seeds + code:0310:05 + cheat + description:Infinite Troopers + code:03D7:08 + cheat + description:Gain 65280 EXP for each kill + code:0086:FF + +cartridge sha256:daa1c7263a804920b2ebeb5b2041da0a207a49b5bcddbfdf51f02ba7e3d89092 + title:Magmax (USA) + cheat + description:Infinite lives - 1P game + code:SZVVYTVG + cheat + description:Infinite lives - 2P game + code:AEEVITPA + cheat + description:Start with 1 life - both players + code:AEKGKLZA + cheat + description:Start with 6 lives - both players + code:IEKGKLZA + cheat + description:Start with 9 lives - both players + code:AEKGKLZE + cheat + description:Infinite lives - P1 + code:0058:02 + cheat + description:Infinite lives - P2 + code:0059:05 + cheat + description:Max upgrades - P1 + code:008B:05 + cheat + description:Max upgrades - P2 + code:008C:05 + +cartridge sha256:84f5377980d2fd44d71faec42f858b1e83540c2f55aba9236c3279d6dde8592a + title:Maniac Mansion (USA) + cheat + description:All codes start out as 0000 + code:SEXGKASZ + +cartridge sha256:7d07d335a873205964299b2735c14fe06170329523341a651f275cdf3ed96f18 + title:Mappy-Land (USA) + cheat + description:Infinite lives + code:SZKXITVG + cheat + description:Start with 1 toy + code:PESXALLA + cheat + description:Start with coins, not toys + code:LESZALAA + cheat + description:Start with fish, not toys + code:PESZALAA + cheat + description:Start with pots, not toys + code:ZESZALAA + cheat + description:Start with 1 life + code:AEXXTAZA + cheat + description:Start with 6 lives + code:IEXXTAZA + cheat + description:Start with 6 toys + code:TESXALLA + +cartridge sha256:d77ed527cf081019dc8e1cad72872ef3bd640114221b89f030e0c03229c54ddc + title:Marble Madness (USA) + cheat + description:Infinite time + code:OXVXLZVS + cheat + description:Don't break from falling + code:EYNGALEI + cheat + description:Cannot fall into bottomless pits + code:OZGGYO+SZAEUA+SZEGPXOX + cheat + description:Extra 20 seconds to complete beginner race + code:GOOZPLAA + cheat + description:Extra 40 seconds to complete beginner race + code:AXOZPLAE + cheat + description:Bonus time not added + code:GXEXTLEL + cheat + description:Infinite time (alt) + code:0044:3C + cheat + description:Max score - P1 + code:004A:63+004B:63+004C:63 + +cartridge sha256:0cc334007d3eae698cdcd034d12ec9bab2b5266e85bc703cf24ccb4e2d63b654 + title:Mario Bros. (World) + cheat + description:Invincibility + code:AVVIEGVI + cheat + description:Infinite time - bonus rounds + code:SZNTPUVK + cheat + description:Infinite power blocks + code:SXNIIZVG + cheat + description:Infinite lives + code:SXTIEG + cheat + description:Move faster + code:PENGSAAA + cheat + description:Move much faster + code:ZENGSAAA + cheat + description:Enemies move faster + code:EZEKEPKZ+ZAEKOPNG + cheat + description:Enemies move much faster + code:EZEKEPKZ+LAEKOPNG + cheat + description:Mega-jump + code:VYSYAUKY+VYSYPUKY + cheat + description:Coins kill you + code:AEUIUGAG + cheat + description:Start with 1 life + code:AAISPL + cheat + description:Start with 6 lives + code:IAISPL + cheat + description:Start with 9 lives + code:AAISPU + cheat + description:Infinite lives - P1 + code:0048:04 + cheat + description:Infinite lives - P2 + code:004C:04 + +cartridge sha256:c9348c4e30ef0bc62c4fd119b5e38d85af493a1eb436c6c229b7a6a52af42681 + title:Mario's Time Machine (USA) + cheat + description:Get an item after killing one Koopa + code:ZEUUGYAA + +cartridge sha256:a385f0bed8d9afd110e649b73084191d80f41728139494f8fcb92d4815cd5197 + title:Master Chu and the Drunkard Hu (USA) (Unl) + cheat + description:Invinicibility + code:SUVOIEVN + cheat + description:Infinite health + code:SLUPANVS + cheat + description:Infinite lives + code:SLXOTYVI + cheat + description:Start on round 2 + code:ZAEALPPA + cheat + description:Start on round 3 + code:LAEALPPA + cheat + description:Start on round 4 + code:GAEALPPA + cheat + description:Start on round 5 + code:IAEALPPA + cheat + description:Start on round 6 + code:TAEALPPA + cheat + description:Start on round 7 + code:YAEALPPA + +cartridge sha256:c8486cd1a35950007a3ba671a128097d780084182a854d6115ddec7dad56e806 + title:Mechanized Attack (USA) + cheat + description:Infinite lives + code:SXUNPEVK + cheat + description:Infinite grenades + code:SZUNTOVK + cheat + description:Infinite bullets + code:SZEYIOVK + cheat + description:Reduce damage by half + code:AEVOAPLA + cheat + description:Magazine holds half normal amount of bullets after first magazine used + code:GPONAOAZ+GPEYLEAZ + cheat + description:Start with only 1 life + code:EZOKIAXZ+PAOKTAAA+KANKPEVE + cheat + description:Start with 6 lives + code:EZOKIAXZ+TAOKTAAA+KANKPEVE + cheat + description:Start with 9 lives + code:EZOKIAXZ+PAOKTAAE+KANKPEVE + cheat + description:Start with only 1 magazine + code:EZOKIAXZ+AAOKTAAA+KANKTEVE + cheat + description:Start with 8 magazines + code:EZOKIAXZ+YAOKTAAA+KANKTEVE + cheat + description:Start with only 1 grenade + code:EZOKIAXZ+PAOKTAAA+KEEGZEVE + cheat + description:Start with 8 grenades + code:EZOKIAXZ+AAOKTAAE+KEEGZEVE + +cartridge sha256:5314ad0c406161195b6bb100ee11304bab8af121bba85992be896d5cb26b109e + title:Mega Man (USA) + cheat + description:Infinite health + code:SZKZGZSA + cheat + description:Invincibility (except against bosses) + code:AVVXLPSZ + cheat + description:Infinite weapons on pick-up + code:IESZXESN + cheat + description:Infinite weapons on pick-up (alt) + code:SUSZSASP + cheat + description:Infinite lives + code:OZSKPZVK + cheat + description:One hit kills + code:AAOGSOLA+ESSUNTEP + cheat + description:One hit kills on bosses + code:AUZYGL + cheat + description:Collectable items never disappear + code:SUULTVVN + cheat + description:Climb up ladders faster + code:PENOAYAA + cheat + description:Climb down ladders faster + code:VYXOXENN + cheat + description:Maximum points for shooting enemies + code:OXSLEEPV+AUSLOEAZ + cheat + description:Mega-jump + code:TAOOYTGA + cheat + description:Multi-jump + code:GOUOTSAP+GXKPVGEL+SUEPLSPX+SOEPGIVP + cheat + description:Enemies always drop extra lives + code:PGOUONLL+XTXLONEK + cheat + description:Enemies always drop large health refill + code:AGOUONLL+XTXLONEK + cheat + description:Enemies always drop large weapon refill + code:XTXLONEK+YLOUONLU + cheat + description:Start with half energy + code:TAXOIOGO + cheat + description:Start with 1 life + code:AASPLAZA + cheat + description:Start with 6 lives + code:IASPLAZA + cheat + description:Start with 9 lives + code:AASPLAZE + cheat + description:Invincibility + code:0055:5A + cheat + description:Infinite health (alt) + code:006A:1C + cheat + description:Infinite lives (alt) + code:00A6:03 + cheat + description:Have all weapons and all stages cleared + code:005D:FF + cheat + description:Bosses have no invulnerability time + code:0056:00 + +cartridge sha256:1e588d435e75d80c5c0b578b4fa8d196f2cf4346c11c9a7b7e435d768828ad01 + title:Mega Man 2 (USA) + cheat + description:Invincibility + code:EIUGVTEY + cheat + description:Invincibility (alt) + code:AIUGVTEY+SAUGKTSZ + cheat + description:Infinite health + code:SXXTPSSE + cheat + description:Infinite lives + code:SXUGTPVG + cheat + description:Infinite Heat Man + code:SXSSOISA + cheat + description:Infinite Air Man + code:SXSSNZSA + cheat + description:Infinite Wood Man + code:SZVIUYSA + cheat + description:Infinite Bubble Man + code:SZUIKLVG + cheat + description:Infinite Quick Man + code:SZVSNLVG + cheat + description:Infinite Metal Man + code:SXKSOLVG + cheat + description:Infinite Clash Man + code:SXESKLVG + cheat + description:Infinite 1 + code:SZNIVGVG + cheat + description:Infinite 2 + code:SZXTGZVG + cheat + description:Infinite 3 + code:SZKTALVG + cheat + description:Burst-fire from normal weapon + code:LZVSSZYZ + cheat + description:Maximum weapon energy on pick-up + code:GZKEYLAL + cheat + description:One hit kills + code:GXETTTEL+GZUZGTEL + cheat + description:Power-jumps + code:TANAOZGA + cheat + description:Super power-jumps + code:AANAOZGE + cheat + description:Mega power-jumps + code:APNAOZGA + cheat + description:Multi-jump + code:AXEAUUSZ+LXEEYIYZ+SEEASLGA+VEEAKLEX + cheat + description:Moonwalking + code:PGEAKOPX + cheat + description:Collectable items never disappear + code:SSNLNKVS + cheat + description:Enemies always drop extra lives + code:ASUNZZEP+SSUNLXKK + cheat + description:Enemies always drop large health refill + code:ASUNZZEP+OSUNLXKK + cheat + description:Enemies always drop large weapon refill + code:ASUNZZEP+SSUNLXKG + cheat + description:Special items re-appear after being collected + code:OUVVASOO + cheat + description:Able to access already defeated boss stages + code:AEVAZEKI + cheat + description:Start with half health + code:TEKAIEGO + cheat + description:Start with 1 life + code:PANALALA + cheat + description:Start with 6 lives + code:TANALALA + cheat + description:Start with 9 lives + code:PANALALE + cheat + description:Invincibility (blinking) + code:004B:02 + cheat + description:Infinite health (alt) + code:06C0:1E + cheat + description:Have all weapons and all stages cleared + code:009A:FF+009B:FF + cheat + description:Infinite Heat Man once obtained + code:009C:1E + cheat + description:Infinite Air Man once obtained + code:009D:1E + cheat + description:Infinite Wood Man once obtained + code:009E:1E + cheat + description:Infinite Bubble Man once obtained + code:009F:1E + cheat + description:Infinite Quick Man once obtained + code:00A0:1E + cheat + description:Infinite Flash Man once obtained + code:00A1:1E + cheat + description:Infinite Metal Man once obtained + code:00A2:1E + cheat + description:Infinite Crash Man once obtained + code:00A3:1E + cheat + description:Infinite 1 once obtained + code:00A4:1E + cheat + description:Infinite 2 once obtained + code:00A5:1E + cheat + description:Infinite 3 once obtained + code:00A6:1E + cheat + description:Infinite energy tanks + code:00A7:03 + cheat + description:Infinite lives (alt) + code:00A8:04 + cheat + description:Atomic Fire always fully charged + code:00AC:FF + cheat + description:Bosses have no invulnerability time + code:05A8:00 + +cartridge sha256:5b85c1ff632c6ac34742ac87b9c8ddee9a13827caf1212ecfa1d11f1f9dece50 + title:Mega Man 3 (USA) + cheat + description:Invincibility + code:ENXETAEI + cheat + description:Infinite health + code:GXVAAASA + cheat + description:Infinite health (alt) + code:SXVAAASA + cheat + description:Infinite lives + code:AEEGXLPA + cheat + description:Infinite weapons (except Top Man) + code:OUNIVVOO + cheat + description:Infinite Top Man + code:SXOAZZSA + cheat + description:Hit anywhere + code:AOSYXUAU+AVSYUUSL + cheat + description:One hit kills + code:AEKEZPZA + cheat + description:Mega-jump + code:YEUKOTGA + cheat + description:Multi-jump + code:TUOKUIYA+VKUGOIES+GZUKOTEP + cheat + description:Longer slides + code:ASXSTLGP + cheat + description:Faster slides + code:NNKIALEE + cheat + description:Move faster + code:NYKGXSGK + cheat + description:Move mega-fast + code:ZAKGNIPA + cheat + description:Collectable items never disappear + code:SIUUNVVS + cheat + description:Enemies always drop extra lives + code:EZNLXYEP+IANLUNPA+TANLVNEY + cheat + description:Enemies always drop large health refill + code:EZNLXYEP+LANLUNPA+TANLVNEY + cheat + description:Enemies always drop large weapon refill + code:EZNLXYEP+PANLUNPA+TANLVNEY + cheat + description:Special items re-appear after being collected + code:AEXOXGKI + cheat + description:Able to access already defeated boss stages + code:AAOOGLSI + cheat + description:Start with 1 life + code:AENKKAZA + cheat + description:Start with 6 lives + code:IENKKAZA + cheat + description:Start with 9 lives + code:AENKKAZE + cheat + description:Start with 1 life after continue + code:PAOONPZA + cheat + description:Start with 6 lives after continue + code:IAOONPZA + cheat + description:Start with 9 lives after continue + code:AAOONPZE + cheat + description:Invincibility (alt) + code:0039:39 + cheat + description:Infinite health (alt 2) + code:00A2:9C + cheat + description:Infinite lives + code:00AE:03 + cheat + description:Infinite slide time + code:0033:FF + cheat + description:Mega-jump (alt) + code:CEB9:09 + cheat + description:Infinite Gemini Man + code:00A3:9C + cheat + description:Infinite Needle Man + code:00A4:9C + cheat + description:Infinite Hard Man + code:00A5:9C + cheat + description:Infinite Magnet Man + code:00A6:9C + cheat + description:Infinite Top Man (alt) + code:00A7:9C + cheat + description:Infinite Snake Man + code:00A8:9C + cheat + description:Infinite Rush Coil + code:00A9:9C + cheat + description:Infinite Spark Man + code:00AA:9C + cheat + description:Infinite Rush Sub + code:00AB:9C + cheat + description:Infinite Shadow Man + code:00AC:9C + cheat + description:Infinite Rush Jet + code:00AD:9C + +cartridge sha256:ed8bc89c9cd44bf566666451779d7db2da3d9c211ff2a4824372c172b554e05b + title:Mega Man 4 (USA) (Rev A) + cheat + description:Infinite health + code:GXVEIPSA + cheat + description:Infinite health (alt) + code:SXVEIPSA + cheat + description:Infinite weapons + code:OUENESOO + cheat + description:Infinite weapon power + code:GXENESOO + cheat + description:Always have 10 E-Tanks + code:VENOEASZ + cheat + description:Infinite lives + code:SZUGUAVG + cheat + description:Infinite energy pods on pick-up + code:GXNPZTVG + cheat + description:Instant full Mega Buster + code:AEOAIEPA + cheat + description:Instant full Mega Buster (alt) + code:LXKESKAP + cheat + description:Hit anywhere + code:APKYKXOU+ATKYSXAZ + cheat + description:Longer slides + code:YXEAIOZO + cheat + description:Shorter slides + code:ZOEAIOZP + cheat + description:Faster slides + code:GEOAGPZA + cheat + description:Mega-jump + code:AAKEYPIE + cheat + description:Multi-jump + code:AUNELEEG+OAEEYPXA+GZUALPEP + cheat + description:Move faster + code:ZANKPTPA+ZEVALLPA + cheat + description:Cosack can't hurt you + code:SXEAEASA + cheat + description:Collectable items never disappear + code:SIUUNVVS + cheat + description:Enemies always drop extra lives + code:AEOLNLTA+LEOUXUEY + cheat + description:Enemies always drop large health refill + code:AEOLNLTA+LEOUXUEY+ZEOLELGA + cheat + description:Enemies always drop large weapon refill + code:AEOLNLTA+LEOUXUEY+IEOLELGA + cheat + description:Special items re-appear after being collected + code:AEXOXGKI + cheat + description:Start with 1 life + code:AAUKZIZA + cheat + description:Start with 6 lives + code:IAUKZIZA + cheat + description:Start with 79 lives + code:AAUKZIZE + cheat + description:Invincibility + code:003C:1F + cheat + description:Infinite health (alt 2) + code:00B0:9C + cheat + description:Infinite lives (alt) + code:00A1:03 + cheat + description:Infinite Bright Man + code:00BC:9C + cheat + description:Infinite Dive Man + code:00B7:9C + cheat + description:Infinite Drill Man + code:00B9:9C + cheat + description:Infinite Dust Man + code:00BA:9C + cheat + description:Infinite Pharaoh Man + code:00BB:9C + cheat + description:Infinite Ring Man + code:00B8:9C + cheat + description:Infinite Skull Man + code:00BD:9C + cheat + description:Infinite Toad Man + code:00B4:9C + cheat + description:Infinite Rush Coil + code:00B1:9C + cheat + description:Infinite Rush Jet + code:00B2:9C + cheat + description:Infinite Rush Marine + code:00B3:9C + cheat + description:Infinite Balloon + code:00B6:9C + cheat + description:Infinite Wire + code:00B5:9C + cheat + description:Infinite time for 1st Balloon + code:046B:FE + cheat + description:Infinite time for 2nd Balloon + code:046A:FE + cheat + description:Infinite time for 3rd Balloon + code:0469:FE + cheat + description:Instant full Mega Buster (alt 2) + code:0559:23 + cheat + description:Bosses have no invulnerability time + code:05CF:00 + +cartridge sha256:a1fda74d03a9dd0c168b1ecae66803d78723cf7ccd85a482dedf017b97e660e8 + title:Mega Man 4 (USA) + cheat + description:Infinite health + code:GXVEIPSA + cheat + description:Infinite health (alt) + code:SXVEIPSA + cheat + description:Infinite weapons + code:OUENESOO + cheat + description:Infinite weapon power + code:GXENESOO + cheat + description:Always have 10 E-Tanks + code:VENOEASZ + cheat + description:Infinite lives + code:SZUGUAVG + cheat + description:Infinite energy pods on pick-up + code:GXNPZTVG + cheat + description:Instant full Mega Buster + code:AEOAIEPA + cheat + description:Instant full Mega Buster (alt) + code:LXKESKAP + cheat + description:Hit anywhere + code:APKYKXOU+ATKYSXAZ + cheat + description:Longer slides + code:YXEAIOZO + cheat + description:Shorter slides + code:ZOEAIOZP + cheat + description:Faster slides + code:GEOAGPZA + cheat + description:Mega-jump + code:AAKEYPIE + cheat + description:Multi-jump + code:AUNELEEG+OAEEYPXA+GZUALPEP + cheat + description:Move faster + code:ZANKPTPA+ZEVALLPA + cheat + description:Collectable items never disappear + code:SIUUNVVS + cheat + description:Enemies always drop extra lives + code:AEOLNLTA+LEOUXUEY + cheat + description:Enemies always drop large health refill + code:AEOLNLTA+LEOUXUEY+ZEOLELGA + cheat + description:Enemies always drop large weapon refill + code:AEOLNLTA+LEOUXUEY+IEOLELGA + cheat + description:Special items re-appear after being collected + code:AEXOXGKI + cheat + description:Start with 1 life + code:AAUKZIZA + cheat + description:Start with 6 lives + code:IAUKZIZA + cheat + description:Start with 9 lives + code:AAUKZIZE + cheat + description:Invincibility + code:003C:1F + cheat + description:Infinite health (alt 2) + code:00B0:9C + cheat + description:Infinite lives (alt) + code:00A1:03 + cheat + description:Infinite Bright Man + code:00BC:9C + cheat + description:Infinite Dive Man + code:00B7:9C + cheat + description:Infinite Drill Man + code:00B9:9C + cheat + description:Infinite Dust Man + code:00BA:9C + cheat + description:Infinite Pharaoh Man + code:00BB:9C + cheat + description:Infinite Ring Man + code:00B8:9C + cheat + description:Infinite Skull Man + code:00BD:9C + cheat + description:Infinite Toad Man + code:00B4:9C + cheat + description:Infinite Rush Coil + code:00B1:9C + cheat + description:Infinite Rush Jet + code:00B2:9C + cheat + description:Infinite Rush Marine + code:00B3:9C + cheat + description:Infinite Balloon + code:00B6:9C + cheat + description:Infinite Wire + code:00B5:9C + cheat + description:Infinite time for 1st Balloon + code:046B:FE + cheat + description:Infinite time for 2nd Balloon + code:046A:FE + cheat + description:Infinite time for 3rd Balloon + code:0469:FE + cheat + description:Instant full Mega Buster (alt 2) + code:0559:23 + cheat + description:Bosses have no invulnerability time + code:05CF:00 + +cartridge sha256:4ddb728c3a007f1aa7184b60a1355cfd376cae46edc007fd48e6bcf41207cdb7 + title:Mega Man 5 (USA) + cheat + description:Infinite health + code:GXSEYZSA + cheat + description:Invincible against spikes + code:SAKEZAIA + cheat + description:Infinite lives + code:GXXAAIVG + cheat + description:Infinite weapons + code:OLKOYSOO+OUNUZSOO+SZSAGZSA + cheat + description:Infinite energy for most weapons + code:OVNLZISV+OTKPYISV + cheat + description:Infinite mega-tanks on pick-up + code:GXSEPZVG + cheat + description:Infinite energy tanks on pick-up + code:GZSATPVG + cheat + description:Hit anywhere + code:APOYYEOU+ATONAEAZ + cheat + description:One hit kills + code:AEUAZOIZ + cheat + description:Starting weapons use less energy + code:PEVLLPGA + cheat + description:Super-jump + code:YEXETAIA+ONUELEUN + cheat + description:Mega-jump + code:PEXETAIA+NNUELEUY + cheat + description:Multi-jump + code:SAKATAIO+EAVEZAXA+GXOAAAEP + cheat + description:Collectable items never disappear + code:ATKXOVVI + cheat + description:Enemies always drop extra lives + code:ASEZVTEP+LEEZETGA + cheat + description:Enemies always drop large health refill + code:ASEZVTEP+PEEZETGA + cheat + description:Enemies always drop large weapon refill + code:ASEZVTEP + cheat + description:Special items re-appear after being collected + code:AEUOVPSI + cheat + description:Start with at least 2 energy tanks + code:XAKSUTEA + cheat + description:Start with at least 6 energy tanks + code:VAKSUTEA + cheat + description:Start with at least 2 mega-tanks + code:XASIOTEA + cheat + description:Start with at least 6 mega-tanks + code:VASIOTEA + cheat + description:Invincibility + code:05B8:2D + cheat + description:Infinite health (alt) + code:00B0:9C + cheat + description:Infinite lives (alt) + code:00BF:03 + cheat + description:Infinite Beat + code:00BC:9C + cheat + description:Infinite Charge Kick + code:00B8:9C + cheat + description:Infinite Crystal Eye + code:00B3:9C + cheat + description:Infinite Gravity Hold + code:00B7:9C + cheat + description:Infinite Gyro Attack + code:00B2:9C + cheat + description:Infinite Napalm Bomb + code:00B4:9C + cheat + description:Infinite Power Stone + code:00B6:9C + cheat + description:Infinite Star Crash + code:00B9:9C + cheat + description:Infinite Super Arrow + code:00B5:9C + cheat + description:Infinite Water Wave + code:00B1:9C + cheat + description:Infinite Rush Coil + code:00BA:9C + cheat + description:Infinite Rush Jet + code:00BB:9C + cheat + description:Bosses have no invulnerability time + code:05C0:00 + +cartridge sha256:2037babe50fed7a13b6f6559914cb81497245c9477592e6f8da183df09a3609a + title:Mega Man 6 (USA) + cheat + description:Invincibility + code:ESXAKTEY + cheat + description:Infinite health + code:SXEAVNSE + cheat + description:Infinite health (except fires, falling into pits and spikes) + code:GXEAKYST + cheat + description:Infinite weapons + code:OUXPXVOO + cheat + description:Infinite Rush Jet + code:SZVAIZVG + cheat + description:Infinite lives (can sometimes die and go to another part of the game) + code:SXEEXTVG + cheat + description:Normal shots do more damage + code:LOOEKGPP + cheat + description:Mega shots do more damage + code:TOKENGLP + cheat + description:Hit anywhere and shoot to pick-up items + code:LEVVNGIA + cheat + description:One hit kills + code:AEVVUUZA+OXVVXLOU + cheat + description:Multi-jump + code:AGEEYOYA+EAOAPOEG+EIOAZPIA+PZOAAOSX+SZEETPEI+XGOALPAU+XTOAGOZE + cheat + description:Collectable items never disappear + code:UKXOTXVI + cheat + description:Enemies always drop extra lives + code:AENAIOPP+YLOEGXPG+YLOELXZG+YLOEPXPL+YLOEZXAL + cheat + description:Enemies always drop large health refill + code:AENAIOPP+PLOEGXPK+PLOEIZYU+PLOELXZK+PLOEZXAU + cheat + description:Enemies always drop large weapon refill + code:AENAIOPP+ZGOEGXPK+ZGOEIZYU+ZGOEPXPU+ZGOEZXAU + cheat + description:Start with 9 lives + code:AAUKVIZE + cheat + description:Start with 6 lives + code:IAUKVIZA + cheat + description:Start with 1 life + code:AAUKVIZA + cheat + description:Invincibility (alt) + code:00A2:36 + cheat + description:Infinite health (alt) + code:03E5:1B + cheat + description:Infinite lives + code:00A9:03 + cheat + description:Super Moonwalk (enable during stages only) + code:05B1:00 + cheat + description:Infinite Beat + code:0689:1B + cheat + description:Infinite C Flash + code:0690:1B + cheat + description:Infinite Centaur + code:0691:1B + cheat + description:Infinite F Blast + code:068C:1B + cheat + description:Infinite Knight + code:068E:1B + cheat + description:Infinite Plant B + code:068D:1B + cheat + description:Infinite W Storm + code:068B:1B + cheat + description:Infinite Yamato + code:068A:1B + cheat + description:Have the Energy Balancer + code:0696:01 + cheat + description:Bosses have no invulnerability time + code:0640:00 + +cartridge sha256:741fbfeeec83073cc3d8b407c0ddc9f78a0dc5b52d8196c6222bffb459b73ed1 + title:Menace Beach (USA) (Unl) + cheat + description:Infinite health and one hit kills (levels 1-9, 11, 12 only) + code:ETVVPOAL+EYVVLPPP+TAVVGPEL+XTVVIPZE+AAVVZPST + cheat + description:Infinite health and one hit kills (level 10 only) + code:ETVVPOAL+EYVVLPPP+TAVVGPEL+XTVVIPZE+PAVVZPST + cheat + description:Multi-jump + code:OZKYPGSX+XAKYZGZT + +cartridge sha256:1152961edf8d484f0e33294ae19fbcac8ab85099e6c8a59f1732c5f17b622885 + title:Mendel Palace (USA) + cheat + description:Infinite lives + code:SLSIXXVS + cheat + description:More stars on pick-up + code:IEXIAIPA + cheat + description:P1 gains P2's speed-ups + code:SZUIOOSU+VTUSEOVN + cheat + description:More lives - P1 + code:KEXLXKSE + cheat + description:More lives - P2 + code:KEXLSKSE + cheat + description:Start with 1 life + code:AAVZLPZA + cheat + description:Start with 5 lives + code:IAVZLPZA + cheat + description:Start with 9 lives + code:AAVZLPZE + cheat + description:Automatically finish level + code:051B:00 + +cartridge sha256:25f5359a73cac2d16ed98940f0b537f0392f232554d457ed476e21a5979419ff + title:Metal Force (K) + cheat + description:Invincibility + code:ENXTTYEI+EYNTZYEI+EYOTNAEI + cheat + description:Invincible against spikes + code:EYSTOAEI + cheat + description:Infinite energy + code:AONPTYAA+GONOLYZE + cheat + description:Infinite lives + code:SXVTZVSE + cheat + description:Keep whatever weapon you started the level with + code:SXUITXSE + cheat + description:Start with max weapon power + code:ZEOAPLAA + cheat + description:Start on Mission 7 + code:YEOATLPA + +cartridge sha256:f6d29afbd7ddad33672852232791a396695de2e77dccb83088a8d6b139d8c9cb + title:Metal Gear (USA) + cheat + description:Infinite health + code:SXVTXZVG+SZUYPZVG + cheat + description:Invincible against Gas + code:SXELYGVG + cheat + description:Invincible against Electric Floors + code:SZSUVZVG + cheat + description:Infinite Rations + code:SXXXETVG + cheat + description:Infinite Handgun ammo + code:SZSVVYVG + cheat + description:Infinite Mines + code:KXEVUTKA + cheat + description:Infinite Explosives + code:VXXVETVA + cheat + description:Infinite Missiles + code:VXVVKTVA + cheat + description:Infinite Machine Gun ammo + code:SZKVXYVG + cheat + description:Infinite Grenades + code:KZEVXYKA + cheat + description:Infinite Rockets + code:VXKVNTVA + cheat + description:Have all weapons + code:OZSXKGXX+NYSXSGAE+SASXVGSZ + cheat + description:Enemies never attack or chase you + code:SLNIUGSP + cheat + description:Hit anywhere - Punch + code:AAETIUUT+AAOTPUNI+AAOVPLNI+ASVVYZEP + cheat + description:Hit anywhere - Weapons except Grenade Launcher + code:AISNYZEY + cheat + description:Start with a health boost + code:XZVSAYVZ+PAVSPNTT+AEKSZYIE + cheat + description:Start with a super health boost + code:XZVSAYVZ+PAVSPNTT+GEKSZYIE + cheat + description:Start at mystery location 1 + code:ZASILYPA + cheat + description:Start at mystery location 2 + code:GASILYPA + cheat + description:Infinite health (alt) + code:006D:10 + cheat + description:Have all equipment + code:0075:FF+0076:FF+0077:FF+0078:0C + cheat + description:Have all weapons (alt) + code:0070:FF + cheat + description:Infinite Handgun ammo (alt) + code:0079:FF + cheat + description:Infinite Mines (alt) + code:007A:0E + cheat + description:Infinite Explosives (alt) + code:007B:0E + cheat + description:Infinite Missiles (alt) + code:007C:0E + cheat + description:Infinite Machine Gun ammo (alt) + code:007D:FF + cheat + description:Infinite Grenades (alt) + code:007E:3C + cheat + description:Infinite Rockets (alt) + code:007F:1E + cheat + description:Have Rank - 0 Stars + code:006E:00 + cheat + description:Have Rank - 1 Star + code:006E:01 + cheat + description:Have Rank - 2 Stars + code:006E:02 + cheat + description:Have Rank - 3 Stars + code:006E:03 + cheat + description:Have Rank - 4 Stars + code:006E:04 + +cartridge sha256:a00c77c3130316625403aeea9a0dbb02acf4a176740dac7b9e9a42452e574d4f + title:Metal Mech - Man & Machine (USA) + cheat + description:Invincibility + code:SZUAXYAX + cheat + description:Infinite health + code:SXNPYNSE+SZVOEESE + cheat + description:Infinite lives - Tony + code:SZEYAVVK + cheat + description:Infinite Smart Bombs + code:SZVYISVK + cheat + description:Super-jumping Tony + code:VNNXTENN + cheat + description:Super-speeding Tony + code:ZEEXGAIA + cheat + description:Mega-speeding Tony + code:PEEXGAIA + cheat + description:Start with 1 life and 1 Smart Bomb + code:PEKSILLA + cheat + description:Start with 6 lives and 6 Smart Bombs + code:TEKSILLA + cheat + description:Start with 9 lives and 9 Smart Bombs + code:PEKSILLE + cheat + description:Start on level 2 + code:AESSAUNY + cheat + description:Start on level 3 + code:PESSAUNY + cheat + description:Start on level 4 + code:ZESSAUNY + cheat + description:Start on level 5 + code:LESSAUNY + cheat + description:Start on level 6 + code:GESSAUNY + cheat + description:Infinite health (alt) + code:05DD:1F + +cartridge sha256:2fbbc465fc239b483cb89582f75451b21276d97868d67f3d8d89c2269fec5e37 + title:Metal Storm (USA) + cheat + description:Invincibility + code:SZNTGTSA+SZOUIYSA + cheat + description:Infinite time + code:SXKNAIVG + cheat + description:Infinite lives + code:AASOYYPA + cheat + description:Slower timer + code:AVKYPSGL + cheat + description:Faster timer + code:AXKYPSGL + cheat + description:Permanent Fireball + code:AESTKXGA + cheat + description:Permanent Shield + code:AESXXNGY + cheat + description:Start with extra weapons + code:NNNLOLAE + cheat + description:Start with 6 lives + code:TEXUNLZA + cheat + description:Start with 9 lives + code:PEXUNLZE + +cartridge sha256:649db8035018f2512ccea70aca6606c3b3a6988cd9ed43953b38dc5103dec7bb + title:Metroid (USA) + cheat + description:Invincibility + code:PZNVGZZN+APKYKKKP+ATEPUVSZ+AVKYXTAZ+AVOYIXSL+AVUYTZAZ+AVVNYZAZ+EPKYUGAZ+EPNVLZKA+OXEPNOOK + cheat + description:Minimum energy of 30 + code:SXSGNVSE + cheat + description:Always have Screw Attack effect + code:AOOKKSAU+AVXGESEA + cheat + description:Infinite Missiles on pick-up + code:SZUILUVK + cheat + description:Hit anywhere + code:AAKYLLLA+GXKNZZEL+NYUNYIAX+SXSYZZAX + cheat + description:Enemies die automatically + code:AAKYPSPZ + cheat + description:Beam has longer range + code:IIAIII + cheat + description:Pick-up items from anywhere + code:GXENAGEY + cheat + description:Gain 10 Missiles on pick-up + code:ZENSXLIE + cheat + description:Gain 15 Missiles on pick-up + code:YENSXLIE + cheat + description:Gain 255 Missiles on pick-up + code:NNNSXLIE + cheat + description:High-jump without High Jump Boots + code:ZONGKNAP + cheat + description:Mega-jump without High Jump Boots + code:GENGKNAO + cheat + description:Mega-jump with High Jump Boots + code:GENKSYZO + cheat + description:Multi-jump + code:GZUIAAEY+GZOGEIEY + cheat + description:No enemies + code:EATTOU + cheat + description:Roll through walls, but loses energy (glitchy) + code:SSAEAI + cheat + description:Start with 70 energy + code:YAXGVPLA + cheat + description:Have all items + code:6878:FF + cheat + description:Infinite energy, Missiles and all items + code:69B2:01 + +cartridge sha256:77c9100f4d3f291dd751098d3291b14e824cc367696c9167d01051041e08b5cb + title:Michael Andretti's World GP (USA) + cheat + description:Infinite time + code:0565:01 + +cartridge sha256:2d40d51736c2fa22f0cccf686e92efee3a7ebb8fa4eee5032206bab099a5aaf6 + title:Mickey Mania 7 (Unl) + cheat + description:Infinite health + code:SXEPTOVK + cheat + description:Infinite lives + code:SZEPYSVK + cheat + description:Infinite Apples + code:SZKPPVVK + +cartridge sha256:826ace604eb7a657acedd98cd3479dbe1d3ebb087dd7a1b2ad299ab854c0d519 + title:Mickey Mouse 3 - Yume Fuusen (Japan) + cheat + description:Invincibility + code:EYNXOYEI + cheat + description:Infinite health (life) + code:SZKEOESE + cheat + description:Infinite lives + code:SZNAKESE + +cartridge sha256:989243c99d6e58c4fbcc6999473e48a389eba22cf1d3cb95dbe4c8b1f3ce15d7 + title:Mickey Mousecapade (USA) + cheat + description:Invincibility + code:ESEPKZEY+ESVPNZEY + cheat + description:Infinite health + code:OVOPPTSV + cheat + description:Infinite lives + code:SZSOPZVG + cheat + description:Mickey and Minnie can shoot on any level + code:GPSIEVGE+LAVSVTZA + cheat + description:Start with 2 lives + code:PESOIPGA + cheat + description:Start with 6 lives + code:IESOIPGA + cheat + description:Start with 9 lives + code:AESOIPGE + +cartridge sha256:1df64e9554fb9997ceeab9954b2b7f8aa6206509a15e09298014ba765d87c094 + title:Micro Machines (USA) (Unl) + cheat + description:Infinite lives + code:GXSZZVVK + cheat + description:Qualify every race + code:GEKYSZZA + cheat + description:Play with 9 lives + code:PEKNAYLE + cheat + description:Ruff Trux after every race + code:PEUYXZLA + cheat + description:Kid out of game after every race + code:PASYNALA + cheat + description:Win Championship race + code:GESYOZPA + cheat + description:Faster Boat acceleration + code:AAOEIAIA + cheat + description:Faster Sports Car acceleration + code:AAOEGAIA + cheat + description:Faster Formula 1 acceleration + code:AAOETAIA + cheat + description:Faster Turbo Wheels(tm) acceleration + code:AAOEYAIA + cheat + description:Faster 4x4 acceleration + code:AAXAAAIA + cheat + description:Faster Tank acceleration + code:AAXAZAZA + cheat + description:Faster Chopper acceleration + code:AAXALAIA + cheat + description:Quicker Boat deceleration + code:AAXATEPA + cheat + description:Quicker Sports Car deceleration + code:AAXAIEPA + cheat + description:Quicker Formula 1 deceleration + code:AAXAYEPA + cheat + description:Quicker Turbo Wheels deceleration + code:AAXEAEPA + cheat + description:Quicker 4x4 deceleration + code:AAXEPEPA + cheat + description:Quicker Tank deceleration + code:AAXELAZA + cheat + description:Quicker Chopper deceleration + code:AAXEGEYA + cheat + description:Higher bounce for Boats + code:YAEAZAPA + cheat + description:Higher bounce for Sports cars + code:IAEAPAPA + cheat + description:Higher bounce for Formula 1's + code:YAEALAPA + cheat + description:Higher bounce for Turbo Wheels + code:YAEAGAPA + cheat + description:Higher bounce for 4x4's + code:YAEAIAPA + cheat + description:Higher bounce for Tanks + code:YAEAYAPA + cheat + description:Drive through vehicles + code:POLESS + cheat + description:Start on race 5 + code:GEKNIYAA + cheat + description:Start on race 10 + code:PEKNIYAE + cheat + description:Start on race 15 + code:TEKNIYAE + cheat + description:Start on race 20 + code:LOKNIYAA + cheat + description:Start on race 25 (Final Race) + code:AOKNIYAE + +cartridge sha256:31b8afd6e571d3ce8ddea49b813ceda2d350df3c84ceb5d8dd2c7a3a6de5ba88 + title:Micro Machines (USA) (Aladdin Compact Cartridge) (Unl) + cheat + description:Infinite lives + code:GZNXGVVK + cheat + description:Qualify every race + code:GAXYSZZA + cheat + description:Play with 9 lives + code:PAXNAYLE + cheat + description:Ruff Trux after every race + code:PAOYXZLA + cheat + description:Kid out of game after every race + code:PEUYYYLA + cheat + description:Win Championship race + code:GAUYOZPA + cheat + description:Faster Boat acceleration + code:AAOEIAIA + cheat + description:Faster Sports Car acceleration + code:AAOEGAIA + cheat + description:Faster Formula 1 acceleration + code:AAOETAIA + cheat + description:Faster Turbo Wheels(tm) acceleration + code:AAOEYAIA + cheat + description:Faster 4x4 acceleration + code:AAXAAAIA + cheat + description:Faster Tank acceleration + code:AAXAZAZA + cheat + description:Faster Chopper acceleration + code:AAXALAIA + cheat + description:Quicker Boat deceleration + code:AAXATEPA + cheat + description:Quicker Sports Car deceleration + code:AAXAIEPA + cheat + description:Quicker Formula 1 deceleration + code:AAXAYEPA + cheat + description:Quicker Turbo Wheels deceleration + code:AAXEAEPA + cheat + description:Quicker 4x4 deceleration + code:AAXEPEPA + cheat + description:Quicker Tank deceleration + code:AAXELAZA + cheat + description:Quicker Chopper deceleration + code:AAXEGEYA + cheat + description:Higher bounce for Boats + code:YAEAZAPA + cheat + description:Higher bounce for Sports cars + code:IAEAPAPA + cheat + description:Higher bounce for Formula 1's + code:YAEALAPA + cheat + description:Higher bounce for Turbo Wheels + code:YAEAGAPA + cheat + description:Higher bounce for 4x4's + code:YAEAIAPA + cheat + description:Higher bounce for Tanks + code:YAEAYAPA + cheat + description:Drive through vehicles + code:POLESS + cheat + description:Start on race 5 + code:GAXNIYAA + cheat + description:Start on race 10 + code:PAXNIYAE + cheat + description:Start on race 15 + code:TAXNIYAE + cheat + description:Start on race 20 + code:LPXNIYAA + cheat + description:Start on race 25 (Final Race) + code:APXNIYAE + +cartridge sha256:a2b4b0fd54028f1bbbdef152d8f2a172270b60162802d298accd0c698d258c3d + title:Mighty Bomb Jack (USA) + cheat + description:Invincibility + code:OXOOYNPX + cheat + description:Invincibility (alt) + code:SXUPPNSE+SZEOXUSE + cheat + description:Infinite lives + code:VZUEZNVK + cheat + description:Infinite time + code:SXXALNVK + cheat + description:Less time in game + code:AKOEGYAT + cheat + description:More time in game + code:EEOEGYAT + cheat + description:Enemies don't return from coin transformation + code:SXOESEVK + cheat + description:Power coins are not used up + code:SZEEXUVK + cheat + description:Disable torture room + code:OESPNTLA + cheat + description:Jump through walls + code:ZEUOUAPA + cheat + description:Start with 1 life + code:PAOEZZLA + cheat + description:Start with 6 lives + code:TAOEZZLA + cheat + description:Start with 9 lives + code:PAOEZZLE + cheat + description:Infinite lives (alt) + code:0295:09 + cheat + description:Infinite time (one's digit) + code:0229:09 + cheat + description:Infinite time (ten's digit) + code:022D:09 + cheat + description:Infinite M's + code:0235:09 + +cartridge sha256:02d86ba60b7f43f9d04131522263e7560d9ad1d4cc474b909d487cc0d470ccc3 + title:Mighty Bomb Jack (Japan) + cheat + description:Invincibility + code:PANPSEPX + cheat + description:Invincibility (alt) + code:SXEPNESE+SXVPSUSE + +cartridge sha256:ef8ccb38760604f5122e034ae0c4591362364632fe2dc2fa10f2660e15bd368f + title:Mighty Final Fight (USA) + cheat + description:Invincibility + code:EAXKNYAA + cheat + description:Infinite lives + code:SZKSNIVG + cheat + description:Infinite credits + code:SZOOLGVG + cheat + description:Protection from most hazards + code:SZXNUPSA + cheat + description:Cody is weaker + code:SZUEAVOU + cheat + description:Cody is stronger + code:EXSEYIKZ+IEVAASLT + cheat + description:Cody is stronger and has a super-powerful normal punch + code:EXSEYIKZ+IEVAASLT+AKEASELA + cheat + description:Cody is much stronger + code:OZUEAVOU+AGUEPTVI+XTUEZTNE + cheat + description:Guy is weaker + code:SZSATVOU + cheat + description:Guy is stronger + code:EZEAYTKZ+IAEEAVLT + cheat + description:Guy is stronger and has a super-powerful normal punch + code:EZEAYTKZ+IAEEAVLT+AGUAKPZA + cheat + description:Guy is much stronger + code:OZSATVOU+AGSAYVEZ+XTSEAVEE + cheat + description:Haggar is weaker + code:SZNAGVOU + cheat + description:Haggar is stronger + code:EZXAYTKZ+LAXEAVLT + cheat + description:Haggar is stronger and has a super-powerful normal punch + code:EZXAYTKZ+LAXEAVLT+AKKEUOIA + cheat + description:Haggar is much stronger + code:OZNAGVOU+AGNAITYI+XTNATVOE + cheat + description:Gain EXP faster (10 pts at a time) (may be displayed incorrectly) + code:OXKAXZSX+AOKAUZIA + cheat + description:Gain EXP much faster (20 pts at a time) (may be displayed incorrectly) + code:OXKAXZSX+AXKAUZIA + cheat + description:Cody starts with 3/4 health (1st life only) + code:ALKGOAAG + cheat + description:Cody starts with 1/2 health (1st life only) + code:AZKGOAAG + cheat + description:Cody starts with 1/4 health (1st life only) + code:APKGOAAG + cheat + description:Cody starts with 3/4 health (after 1st life) + code:ALKSKTAG + cheat + description:Cody starts with 1/2 health (after 1st life) + code:AZKSKTAG + cheat + description:Cody starts with 1/4 health (after 1st life) + code:APKSKTAG + cheat + description:Guy starts with 3/4 health (1st life only) + code:GZKGXAAL + cheat + description:Guy starts with 1/2 health (1st life only) + code:APKGXAAU + cheat + description:Guy starts with 1/4 health (1st life only) + code:GAKGXAAU + cheat + description:Guy starts with 3/4 health (after 1st life) + code:GZSIXTAL + cheat + description:Guy starts with 1/2 health (after 1st life) + code:APSIXTAU + cheat + description:Guy starts with 1/4 health (after 1st life) + code:GASIXTAU + cheat + description:Haggar starts with 3/4 health (1st life only) + code:GLKGUAAS + cheat + description:Haggar starts with 1/2 health (1st life only) + code:AZKGUAAS + cheat + description:Haggar starts with 1/4 health (1st life only) + code:GPKGUAAI + cheat + description:Haggar starts with 3/4 health (after 1st life) + code:GLSSETAS + cheat + description:Haggar starts with 1/2 health (after 1st life) + code:AZSSETAS + cheat + description:Haggar starts with 1/4 health (after 1st life) + code:GPSSETAI + cheat + description:Start with 2 lives (doesn't work on continues) + code:PEVKTYIA + cheat + description:Start with 4 lives (doesn't work on continues) + code:LEVKTYIA + cheat + description:Start with 8 lives (doesn't work on continues) + code:YEVKTYIA + cheat + description:Start with 10 lives (doesn't work on continues) + code:PEVKTYIE + cheat + description:Start with 1 credit + code:PENGZYLA + cheat + description:Start with 5 credits + code:IENGZYLA + cheat + description:Start with 7 credits + code:YENGZYLA + cheat + description:Start with 9 credits + code:PENGZYLE + cheat + description:Invincibility (alt) + code:003B:25 + cheat + description:Infinite health + code:003A:30 + cheat + description:Infinite lives (alt) + code:003E:09 + cheat + description:Max level + code:006B:05 + +cartridge sha256:5327792d8b5392cd5cec95ee254fc9f729777283c80f3d1f94d5147f3be73652 + title:MiG 29 - Soviet Fighter (USA) (Unl) + cheat + description:Keep weapon after death + code:SZSSOLVG + cheat + description:Start with best weapon + code:LANKPPAA + cheat + description:More time to refuel + code:NNEOZAAE + cheat + description:Less time to refuel + code:LEEOZAAA + cheat + description:Start with 1 life + code:AANGGPLA + cheat + description:Start with 6 lives + code:IANGGPLA + cheat + description:Start with 9 lives + code:AANGGPLE + cheat + description:Start with 255 lives + code:VYNGGPLE + cheat + description:Start on mission 2 + code:OZOOYPSX+PAXPAPIP+XIXPZPPS + cheat + description:Start on mission 3 + code:OZOOYPSX+ZAXPAPIP+XIXPZPPS + cheat + description:Start on mission 4 + code:OZOOYPSX+LAXPAPIP+XIXPZPPS + cheat + description:Start on mission 5 + code:OZOOYPSX+GAXPAPIP+XIXPZPPS + cheat + description:Start on mission 6 + code:OZOOYPSX+IAXPAPIP+XIXPZPPS + +cartridge sha256:2ebab487204c42b0d9cf19c37bdc395e396226ca3eaa664907bf7f8216b3c4d3 + title:Mike Tyson's Punch-Out!! (Japan, USA) (Rev A) + cheat + description:Infinite health + code:ATEALIXZ + cheat + description:Infinite hearts + code:PAXEUPAE + cheat + description:Infinite hearts (alt) + code:GZKETGST + cheat + description:Infinite stars + code:AAVEAOTP + cheat + description:Infinite stars once obtained + code:ALNEVPEY + cheat + description:Infinite time + code:XXXELNVA+SUSETNSO + cheat + description:Infinite time (alt) + code:SUSETNSO + cheat + description:Opponent cannot block punches + code:INUAIZSY + cheat + description:No health for opponent + code:ATOEXESA+SXKAYKSE + cheat + description:No health replenishment for opponent + code:SZSELPAX + cheat + description:Take less damage + code:SZVAAOIV + cheat + description:Take even less damage + code:SZVALPAX + cheat + description:Normal punches do more damage + code:AAVETLGA + cheat + description:Instant win + code:YZLOSS + cheat + description:Instant loss + code:UZLOSS + cheat + description:First knockdown will be a TKO + code:AXIONS + cheat + description:Start with and have infinite stars + code:ALVAYPEY + cheat + description:Start each round with 3 stars + code:LASAEPAA + cheat + description:Infinite health (alt) + code:0391:60 + cheat + description:Infinite hearts (alt 2) + code:0324:0A + cheat + description:Infinite time + code:0305:00+0306:00+0307:00 + cheat + description:No health for opponent (alt) + code:0398:00 + cheat + description:First knockdown will be a TKO + code:03CA:02+03D1:02 + cheat + description:Start with and infinite stars + code:0342:03 + cheat + description:Start on match 02 - Von Keiser + code:0001:01 + cheat + description:Start on match 03 - Piston Honda + code:0001:02 + cheat + description:Start on match 04 - Don Flamenco + code:0001:03 + cheat + description:Start on match 05 - King Hippo + code:0001:04 + cheat + description:Start on match 06 - Great Tiger + code:0001:05 + cheat + description:Start on match 07 - Bald Bull + code:0001:06 + cheat + description:Start on match 08 - Piston Honda (2nd match) + code:0001:07 + cheat + description:Start on match 09 - Soda Popinski + code:0001:08 + cheat + description:Start on match 10 - Bald Bull (2nd match) + code:0001:09 + cheat + description:Start on match 11 - Don Flamenco (2nd match) + code:0001:0A + cheat + description:Start on match 12 - Mr. Sandman + code:0001:0B + cheat + description:Start on match 13 - Super Macho Man + code:0001:0C + cheat + description:Start on match 14 - Mike Tyson + code:0001:0D + +cartridge sha256:752f9d07450e6ec075b109f5be1b1933e8385ad687ceaf24f70a590767bb5a27 + title:Mike Tyson's Punch-Out!! (Japan, USA) + cheat + description:Infinite health + code:ATEALIXZ + cheat + description:Infinite hearts + code:PAXEUPAE + cheat + description:Infinite hearts (alt) + code:GZKETGST + cheat + description:Infinite stars + code:AAVEAOTP + cheat + description:Infinite stars once obtained + code:ALNEVPEY + cheat + description:Infinite time + code:XXXELNVA+SUSETNSO + cheat + description:Infinite time (alt) + code:SUSETNSO + cheat + description:Opponent cannot block punches + code:INUAIZSY + cheat + description:No health for opponent + code:ATOEXESA+SXKAYKSE + cheat + description:No health replenishment for opponent + code:SZSELPAX + cheat + description:Take less damage + code:SZVAAOIV + cheat + description:Take even less damage + code:SZVALPAX + cheat + description:Normal punches do more damage + code:AAVETLGA + cheat + description:Start with and have infinite stars + code:ALVAYPEY + cheat + description:Start each round with 3 stars + code:LASAEPAA + cheat + description:Infinite health (alt) + code:0391:60 + cheat + description:Infinite hearts (alt 2) + code:0324:0A + cheat + description:Infinite time + code:0305:00+0306:00+0307:00 + cheat + description:No health for opponent (alt) + code:0398:00 + cheat + description:First knockdown will be a TKO + code:03CA:02+03D1:02 + cheat + description:Start with and infinite stars + code:0342:03 + cheat + description:Start on match 02 - Von Keiser + code:0001:01 + cheat + description:Start on match 03 - Piston Honda + code:0001:02 + cheat + description:Start on match 04 - Don Flamenco + code:0001:03 + cheat + description:Start on match 05 - King Hippo + code:0001:04 + cheat + description:Start on match 06 - Great Tiger + code:0001:05 + cheat + description:Start on match 07 - Bald Bull + code:0001:06 + cheat + description:Start on match 08 - Piston Honda (2nd match) + code:0001:07 + cheat + description:Start on match 09 - Soda Popinski + code:0001:08 + cheat + description:Start on match 10 - Bald Bull (2nd match) + code:0001:09 + cheat + description:Start on match 11 - Don Flamenco (2nd match) + code:0001:0A + cheat + description:Start on match 12 - Mr. Sandman + code:0001:0B + cheat + description:Start on match 13 - Super Macho Man + code:0001:0C + cheat + description:Start on match 14 - Mike Tyson + code:0001:0D + +cartridge sha256:bd84b27f752aa568374e1c8a6df948340a1374478b754f2ddc32e37d75b4a2b9 + title:Millipede (USA) + cheat + description:Infinite lives - both players + code:SUKGETVI + cheat + description:Increase territory to half screen + code:ASESIIEZ + cheat + description:Increase territory to full screen + code:AXESIIEZ + cheat + description:Shrink territory + code:NKESIIEZ + cheat + description:Player's bullets move faster + code:ZEUSXYTE + cheat + description:Player's bullets move slower + code:LEUSXYTA + cheat + description:Start with 1 life - P1 + code:PAVKSPGA + cheat + description:Start with 10 lives - P1 + code:ZAVKSPGE + +cartridge sha256:6eea421f6c0738ff3abfd6e059e91c3409eedd2150093d3e01d49dfaad4dbf80 + title:Milon's Secret Castle (USA) + cheat + description:Infinite health + code:SZNSLZSA + cheat + description:More health on pick-up + code:AOKGNXAE + cheat + description:No health on pick-up + code:AEKGNXAA + cheat + description:Max power bubbles + code:ASEZZYEI + cheat + description:Hit anywhere + code:ESUIGOOG+GXUIIOAA + cheat + description:Floating Milon + code:ASNPVZLA + cheat + description:Start with more health + code:AGSEEZAZ + cheat + description:Start with a bigger health bar + code:AISAOXAL + cheat + description:Infinite health (alt) + code:00B2:3F + cheat + description:Doors always unlocked + code:07BF:FF + cheat + description:Set money to $900 + code:00A1:09 + cheat + description:Have all Crystals + code:07B7:FA + cheat + description:Have Blimp Ship + code:07A6:FA + cheat + description:Have Feather + code:07A4:FA + cheat + description:Have Hammer + code:07A0:FA + cheat + description:Have Ice Bottle + code:07A8:FA + cheat + description:Have Jump Shoes + code:079A:FA + cheat + description:Have Lantern + code:079F:FA + cheat + description:Have Medicine + code:079D:FA + cheat + description:Have Roller Shoes + code:079B:FA + cheat + description:Have Saw + code:079C:FA + cheat + description:Have Sword + code:07A7:FA + cheat + description:Have Tube + code:07A5:FA + cheat + description:Have Vest + code:07A3:FA + +cartridge sha256:61e4e0a38f23eec3e931f21ad89cc901ca9f709dccfec952ed0e478172f04441 + title:Mission Cobra (USA) (Unl) + cheat + description:Infinite health + code:AANNZPGT+AAESVIGT+AAXIOLGT + cheat + description:Infinite health (alt) + code:009A:63 + +cartridge sha256:6b04b87ab30e885974844ad693cc39ba8c87e7e650e1f9cf22a054e0a385df4e + title:Mission Impossible (USA) + cheat + description:Infinite Type B weapons for all + code:AAUPIZPA + cheat + description:Take less damage + code:SXUETVOU + cheat + description:Take more damage + code:ZENETTPA + cheat + description:2 Type B weapons for Nicholas + code:ZEULXGIA + cheat + description:9 Type B weapons for Nicholas + code:PEULXGIE + cheat + description:5 Type B weapons for Max and Grant + code:IEXUXKZA + cheat + description:15 Type B weapons for Max and Grant + code:YEXUXKZE + cheat + description:Longer disguise time + code:VKOAVOSX+GAEOPLPA + cheat + description:Start with less health + code:TEOUNKGA + cheat + description:Start with more health + code:AOOUNKGA + cheat + description:Infinite health + code:03EC:0D+03ED:0D+03EE:0D + cheat + description:Infinite weapons + code:03F5:0A+03F6:0A+03F7:09 + +cartridge sha256:0bd6257a4566c57c582421bfbf8e81a5491a94e13f4e7a9378c3332c70884532 + title:Mitsume ga Tooru (Japan) + cheat + description:Hit anywhere + code:AEULXZLA + cheat + description:Collect money from anywhere + code:AIXALGEL+ALVEOIEL + cheat + description:Start a new game for hidden debug TEST MODE menu + code:LAKAPLGA + cheat + description:Start a new game to view the ending + code:YAKAPLGA + +cartridge sha256:f997fe34edf1d998694aa979c81fe0063480274b4284498f230fffe694fe87ac + title:Monopoly (USA) + cheat + description:Collect $300 as you pass Go + code:YLSSOLPU + cheat + description:Collect $100 as you pass Go + code:IPSSOLPU + cheat + description:Pay $0 to get out of jail + code:AAVZKAYP + cheat + description:Pay $100 to get out of jail + code:IPVZKAYO + cheat + description:Pay $30 for luxury tax + code:LOOAVKZP + cheat + description:Pay $100 for luxury tax + code:IOOAVKZO + cheat + description:Pay $200 for luxury tax + code:PUOAVKZP + cheat + description:Pay $0 for income tax + code:AESAVGPL + cheat + description:Pay $30 for income tax + code:LOSAVGPL + cheat + description:Pay $100 for income tax + code:IOSAVGPU + cheat + description:Pay $300 for income tax + code:YUSAVGPU + cheat + description:$300 to buy Boardwalk + code:YLOSLKLK + cheat + description:$600 to buy Boardwalk + code:LIOSLKLG + cheat + description:$200 to buy Park Place + code:PLOIZGIG + cheat + description:$400 to buy Park Place + code:LGOIZGIK + cheat + description:$600 to buy Park Place + code:LIOIZGIG + cheat + description:Houses on Park Place cost $100 + code:IPOSZGPU + cheat + description:Houses on Park Place cost $300 + code:YLOSZGPU + cheat + description:Houses on Boardwalk cost $100 + code:IPXILGPU + cheat + description:Houses on Boardwalk cost $300 + code:YLXILGPU + cheat + description:Go Back 7 spaces instead of 3 on Chance + code:YAOAILLA + +cartridge sha256:08615e9e339bd2df713cdb15f6426895ba643fbd8f383758f7f5c06ebf7ac10b + title:Monster in My Pocket (USA) + cheat + description:Invincibility after first hit + code:SUKEPSVS+OOVAPTEP + cheat + description:Infinite energy + code:SUSEIVVS + cheat + description:Infinite lives + code:SLSAASVS + +cartridge sha256:219c94a1f0801ee255f4c8df6d7d1120bdcfd882fcaecba2c858b1e4c66d060b + title:Monster Party (USA) + cheat + description:Invincibility + code:AVOEZYSZ + cheat + description:Infinite life against normal enemies + code:SXXAYYVG + cheat + description:Infinite life against Guardians + code:VVXAIYVG + cheat + description:One hit kills normal enemies + code:EYEEIIEL + cheat + description:One hit kills Guardians + code:AAUEUIZA + cheat + description:Walk twice as fast + code:VNKETXNN+ZEUEAZPA + cheat + description:Jump twice as far + code:VNNAZKNN+ZESEYGPA + cheat + description:Start with double life + code:APUPZSGE+AOKPTKGE + cheat + description:Start with full life + code:GZUPZSGE+GXKPTKGE + cheat + description:Start on level 2 + code:PAKOZIAA + cheat + description:Start on level 3 + code:ZAKOZIAA + cheat + description:Start on level 4 + code:LAKOZIAA + cheat + description:Start on level 5 + code:GAKOZIAA + cheat + description:Start on level 6 + code:IAKOZIAA + cheat + description:Start on level 7 + code:TAKOZIAA + cheat + description:Start on level 8 + code:YAKOZIAA + +cartridge sha256:66cb74efa264a285a541277b935d4b6cc9c49a18653bce90b65f0de98b05aec0 + title:Moon Ranger (USA) (Unl) + cheat + description:Infinite lives + code:SXUSGVVK + +cartridge sha256:aa0fe1b0b1e0c3a0a01695f1914fbb5e92649db33b74a9bdcb51be1481221f49 + title:Mother (Japan) + cheat + description:Start a new game with $1024 + code:GAOLOTAA + cheat + description:Start a new game with $16,384 + code:AGOLOTAA + +cartridge sha256:ed219a1b03be92e3ac4a2229e3e7663fd126eca6332f0564e5d3a12ec56f2142 + title:MotorCity Patrol (USA) + cheat + description:Don't take damage + code:AEEXGTPA + cheat + description:Slow down timer + code:ANOEIOGL + cheat + description:Speed up timer + code:YOOEIOGU + cheat + description:Free equipment + code:GXUESKVK+APUAUGEI + cheat + description:Start with 5 merits + code:IAOXILAA + +cartridge sha256:3264e4c57ffaf64df816cc97b1d6d278042545a4be248f5c195d82037f0a9bfd + title:Mr. Gimmick (Europe) + cheat + description:Invincibility + code:EIOAAGEY+VTOAZKVK + cheat + description:Infinite health + code:SKOEEKVK + cheat + description:Infinite lives + code:SKVTTSVK + cheat + description:Start with 3 Bombs + code:LEVTIAAA + cheat + description:Start with 3 Fireballs + code:ZEVTIAAA + cheat + description:Start with 3 Potions + code:PEVTIAAA + cheat + description:Invincibility (alt) + code:038C:02 + cheat + description:Infinite health (alt) + code:0346:04 + cheat + description:Infinite lives (alt) + code:0104:09 + +cartridge sha256:f7cc35a736ffd7804056b92ab92bfef02ded95d999ac126b680e87b573f18182 + title:Ms. Pac-Man (USA) + cheat + description:Infinite lives - P1 + code:003F:06 + cheat + description:Infinite lives - P2 + code:004F:06 + cheat + description:Power pill effect always active + code:00CF:0F + cheat + description:Start on stage 02 + code:003E:02 + cheat + description:Start on stage 03 + code:003E:03 + cheat + description:Start on stage 04 + code:003E:04 + cheat + description:Start on stage 05 + code:003E:05 + cheat + description:Start on stage 06 + code:003E:06 + cheat + description:Start on stage 07 + code:003E:07 + cheat + description:Start on stage 08 + code:003E:08 + cheat + description:Start on stage 09 + code:003E:09 + cheat + description:Start on stage 10 + code:003E:0A + +cartridge sha256:3ec56ffa686a0e45dc5dfa02d3216b6c9302177b01a0bba506739a436c4ba730 + title:Ms. Pac-Man (USA) (Unl) + cheat + description:Infinite lives for both players in alternating type games + code:SXNETZVG + cheat + description:Infinite lives for P2 only, in other type games + code:SZEALUVK + cheat + description:Super fast turbo speed + code:XVONINZK + cheat + description:Pinky out of game + code:AAUEZTZA + cheat + description:Sue out of game + code:AASEZTZA + cheat + description:Start with 1 life - both players + code:AEUAYTZA + cheat + description:Start with 6 lives - both players + code:IEUAYTZA + cheat + description:Start with 9 lives - both players + code:AEUAYTZE + cheat + description:Start with 1 life for P2 in 2P cooperative and competitive games + code:KEUEZVSE + cheat + description:Only pink ghost escapes from center + code:002A:1B+023D:0E+002C:0B + cheat + description:Max score - P1 + code:00D0:09+00D1:99+00D2:99 + cheat + description:Infinite lives + code:00D4:09 + cheat + description:Start on level 2 + code:0127:01 + cheat + description:Start on level 3 + code:0127:02 + cheat + description:Start on level 4 + code:0127:03 + cheat + description:Start on level 5 + code:0127:04 + cheat + description:Start on level 6 + code:0127:05 + +cartridge sha256:80f6f2b9cb2669e876328cf47ad94fd5288adeddaf45dee93087142ff589b6d6 + title:Muppet Adventure - Chaos at the Carnival (USA) + cheat + description:Infinite power + code:SZKANZVG + +cartridge sha256:ac2374bd4a5f7c87a7bd51e296f79800f84ea6c91a35e0c79dd9a3b2f923ef37 + title:Mutant Virus, The - Crisis in a Computer World (USA) + cheat + description:Invincibility + code:SXEKXGVG + cheat + description:Infinite health + code:SZKGNUSE + cheat + description:Infinite time + code:VXEITKVE + cheat + description:Infinite lives + code:XVEITKVE + cheat + description:Don't flash after getting hit + code:AEESZKNY + cheat + description:Flash 1/2 as long after getting hit + code:LVESZKNY + cheat + description:Start with 1 life + code:AEOGTAIA + cheat + description:Start with 3 lives + code:ZEOGTAIA + cheat + description:Start with 7 lives + code:SEOGTAIA + cheat + description:Start with 10 lives + code:PEOGTAIE + cheat + description:Infinite health (alt) + code:0119:0C + cheat + description:Infinite lives (alt) + code:0110:06 + +cartridge sha256:61cb18d11771cffa08f79fd6973f634c8351703a2fe0f79858171d72a5a46582 + title:Mystery Quest (USA) + cheat + description:Invincibility + code:GXNPYAVG + cheat + description:Infinite vitality + code:SXNPYAVG + cheat + description:Immune to monster attacks + code:AEXOGEEY + cheat + description:Immune to shallow water + code:AEUOAENY + cheat + description:Never lose Key + code:GXVOOYSA + cheat + description:Never lose Raft + code:PENOPTAA + cheat + description:Start with more vitality + code:ATSEUYAG + cheat + description:Start with less vitality + code:AZSEUYAG + cheat + description:Start with Raft and Key + code:PEUOKPAA + +cartridge sha256:dc71dadc3f4eae03f26ac4afec8ef044e7874ad8fdee1567a9b9b9e2c112669e + title:NARC (USA) + cheat + description:Invincibility (blinking) - both players + code:AENXPOTA + cheat + description:Infinite health - both players + code:XVXVGLVN + cheat + description:Infinite Bullets + code:AAOSUPPA + cheat + description:Infinite Missiles + code:AEEILGPA + cheat + description:Infinite lives + code:SUKVTLVI + cheat + description:Enemies die automatically + code:ASUSNYEY+PSKIEYUY + cheat + description:Hit anywhere - P1 + code:AASTAPLA+ASKIOYKZ+YKKIXYTS + cheat + description:More missiles + code:PUVAGAIU + cheat + description:1 Missile on pick-up + code:PEUZPZIA + cheat + description:9 Missiles on pick-up + code:PEUZPZIE + cheat + description:45 Bullets on pick-up + code:GASPTLZA + cheat + description:Start with 1 life + code:AAUAZPZA + cheat + description:Start with 6 lives + code:IAUAZPZA + cheat + description:Start with 9 lives + code:AAUAZPZE + +cartridge sha256:55efed163edb02abc2a344aba79edc5ad873a77ed92378ad0c3e62f1e1816d3e + title:NES Open Tournament Golf (USA) + cheat + description:Always on first shot + code:PEUAGVSP + cheat + description:No wind + code:SZKINZSA + +cartridge sha256:4b382baa70cbc52977fd766f49a3c7c9a3239f0d9581cd961b8b26700c53247d + title:NES Play Action Football (USA) + cheat + description:30-minute quarters + code:TOKYLKYE + cheat + description:10-minute quarters + code:ZEKYLKYE + cheat + description:No timeouts - P2 + code:KEKLUNSE + cheat + description:6 timeouts per half (ignore display) + code:TEUUNYLA + cheat + description:1 timeout per half + code:PEUUNYLA + +cartridge sha256:c03ffd0d5fb5439eb35f22f09df3cbd8f81f5cf3eb9b6718a4d7afb67c75c543 + title:Nigel Mansell's World Championship Challenge (USA) + cheat + description:Almost no tire wear + code:SZSTLEVK+SZNNXEVK + cheat + description:Only need 1 lap on all tracks + code:ZANKXZYA+SXNKSESU + cheat + description:Accelerate faster + code:IVSNIOIN + cheat + description:Accelerate a lot faster + code:IVSNIOIN+AAKNALGE + cheat + description:No extra time in the pits + code:GZSULOVV + cheat + description:Less tire wear + code:SZSTLEVK + cheat + description:Only need 3 laps in South Africa instead of 6 + code:GANKXZYA + cheat + description:Only need 3 laps in Mexico instead of 6 + code:GANKUZYA + cheat + description:Only need 3 laps in Brazil instead of 5 + code:GANKKZTA + cheat + description:Only need 3 laps in Spain instead of 4 + code:GANKSZIA + cheat + description:Only need 3 laps in San Marino instead of 6 + code:GANKVZYA + cheat + description:Only need 3 laps in Monaco instead of 5 + code:GANKNZTA + cheat + description:Only need 3 laps in Canada instead of 6 + code:GEEGEZYA + cheat + description:Only need 3 laps in France instead of 4 + code:GEEGOZIA + cheat + description:Only need 3 laps in Great Britian instead of 5 + code:GEEGXZTA + cheat + description:Only need 3 laps in Germany instead of 5 + code:GEEGUZTA + cheat + description:Only need 3 laps in Hungary instead of 5 + code:GEEGKZTA + cheat + description:Only need 3 laps in Belgium instead of 5 + code:GEEGSZTA + cheat + description:Only need 3 laps in Italy instead of 6 + code:GEEGVZYA + cheat + description:Only need 3 laps in Portugal instead of 4 + code:GEEGNZIA + cheat + description:Only need 3 laps in Japan instead of 5 + code:GEEKEZTA + cheat + description:Only need 3 laps in Australia instead of 5 + code:GEEKOZTA + cheat + description:Full season ends after South Africa + code:PEOXOZAP + cheat + description:Full season ends after Mexico + code:ZEOXOZAP + cheat + description:Full season ends after Brazil + code:LEOXOZAP + cheat + description:Full season ends after Spain + code:GEOXOZAP + cheat + description:Full season ends after San Marino + code:IEOXOZAP + cheat + description:Full season ends after Monaco + code:TEOXOZAP + cheat + description:Full season ends after Canada + code:YEOXOZAP + cheat + description:Full season ends after France + code:AEOXOZAO + cheat + description:Full season ends after Great Britian + code:PEOXOZAO + cheat + description:Full season ends after Germany + code:ZEOXOZAO + cheat + description:Full season ends after Hungary + code:LEOXOZAO + cheat + description:Full season ends after Belgium + code:GEOXOZAO + cheat + description:Full season ends after Italy + code:IEOXOZAO + cheat + description:Full season ends after Portugal + code:TEOXOZAO + cheat + description:Full season ends after Japan + code:YEOXOZAO + cheat + description:Start with 1/2 normal tire tread + code:AEEKXAAO + +cartridge sha256:58be6a811ee3370882160115253b610581e8b4af7228669eb3fbd56e7a13117c + title:Nightmare on Elm Street, A (USA) + cheat + description:Invincibility + code:EIOLILEY + cheat + description:Infinite health + code:SUUUKNVN + cheat + description:Infinite lives + code:SUELSUVS + cheat + description:Infinite 'zzz' + code:SZUPPEVS + cheat + description:Have all characters + code:ESVLNPEY+ENSUOPEI + cheat + description:Hit anywhere + code:AAOKENIA+APXGEYEY+ASNKKTEY + cheat + description:One hit kills + code:EIVKKYEY + cheat + description:No enemies + code:AEOXAPIA+OXOZYOSX+XVOXPPPE + cheat + description:Always able to switch characters + code:AUKUVPEY + cheat + description:Freddy will not show up in Nightmare World + code:SXNTPEVK + cheat + description:Mega-jumping teenagers + code:IEULIGLA + cheat + description:Don't lose 'zzz' when hit + code:AESSLAEA + cheat + description:Don't lose 'zzz' when standing still + code:AAXOLAPA + cheat + description:Lose 'zzz' quicker + code:ZAXOLAPA + cheat + description:Start with 1 continue + code:PAUVEZLA + cheat + description:Start with 6 continues + code:TAUVEZLA + cheat + description:Start with 9 continues + code:PAUVEZLE + +cartridge sha256:02caaf66cc43a4c5a8d54252fca7bcb929dad91c71f127eabe37f29ef9199105 + title:Nightshade (USA) + cheat + description:Invincible in fights + code:TKISGT + cheat + description:Invincible out of fights + code:TKISAI + +cartridge sha256:b1c2ae757c5ec76f488893f130f0f7f1aacf36a25467b9012ca3a11ab52204ce + title:Ninja Crusaders (USA) + cheat + description:Invincibility + code:EYSKYAEI + cheat + description:Infinite lives + code:SLKKAOVS + cheat + description:Mega-jump + code:IZNXNTZP + cheat + description:Super speed + code:SYXESUVN+ZAXEULPA + cheat + description:Start with 1 life + code:PEOZEALA + cheat + description:Start with 6 lives + code:TEOZEALA + cheat + description:Start with 9 lives + code:PEOZEALE + cheat + description:Start on stage 1-2 + code:PAEPTGAA + cheat + description:Start on stage 2-1 + code:ZAEPTGAA + cheat + description:Start on stage 2-2 + code:LAEPTGAA + cheat + description:Start on stage 3-1 + code:GAEPTGAA + cheat + description:Start on stage 3-2 + code:IAEPTGAA + cheat + description:Start on stage 4-1 + code:TAEPTGAA + cheat + description:Start on stage 4-2 + code:YAEPTGAA + cheat + description:Start on stage 5-1 + code:AAEPTGAE + +cartridge sha256:6799437d4122b81c86ae35cefe5b6ae6e10e6f9a9c7b3140dd569f717ba32b3d + title:Ninja Gaiden (USA) + cheat + description:Invincibility + code:OZTTZO + cheat + description:Invincibility (alt) + code:ATNTYOOZ + cheat + description:Infinite health + code:SXXVYPSA + cheat + description:Infinite lives + code:SZETPGVG + cheat + description:Hit anywhere + code:AEIIST+AETIUT+AETSUT+AOYIUT+ESYINT + cheat + description:Enemies die instantly + code:AENIXILA+AESISTGZ+AEVIUTIP+AEVSUVPA+AONIUTEP+ESNINTEP + cheat + description:Multi-jump + code:AEEVSLEA+AEOTXSIP+GXVVSGEI+GZUTSTEI+SXNTVTSA + cheat + description:Use windmill throwing-star without losing spiritual strength + code:AEXVVYIA + cheat + description:Use fire-wheel without losing spiritual strength + code:AAETUYIA + cheat + description:Use shuriken without losing spiritual strength + code:AAVTNYLA + cheat + description:Maximum strength regained from restorer + code:APEIKGTA + cheat + description:Sound Test - hold down and press Start at Tecmo Presents screen + code:GASETAVT + cheat + description:Start with 9 lives + code:AAUVLIZE + cheat + description:Start with 6 lives + code:IAUVLIZA + cheat + description:Start with 1 life + code:AAUVLIZA + cheat + description:Invincibility after first hit + code:0092:02+0093:80 + cheat + description:One hit kills bosses + code:0497:00 + cheat + description:Start on stage 1-2 + code:006D:01 + cheat + description:Start on stage 2-1 + code:006D:02 + cheat + description:Start on stage 2-2 + code:006D:03 + cheat + description:Start on stage 2-3 + code:006D:04 + cheat + description:Start on stage 3-1 + code:006D:05 + cheat + description:Start on stage 3-2 + code:006D:06 + cheat + description:Start on stage 3-3 + code:006D:07 + cheat + description:Start on stage 4-1 + code:006D:08 + cheat + description:Start on stage 4-2 + code:006D:09 + cheat + description:Start on stage 4-3 + code:006D:0A + cheat + description:Start on stage 4-4 + code:006D:0B + cheat + description:Start on stage 5-1 + code:006D:0C + cheat + description:Start on stage 5-2 + code:006D:0D + cheat + description:Start on stage 5-3 + code:006D:0E + cheat + description:Start on stage 5-4 + code:006D:0F + cheat + description:Start on stage 6-1 + code:006D:10 + cheat + description:Start on stage 6-2 + code:006D:11 + cheat + description:Start on stage 6-3 + code:006D:12 + cheat + description:Start on stage 6-4 (1st boss) + code:006D:13 + cheat + description:Start on stage 6-4 (2nd boss) + code:006D:14 + cheat + description:Start on stage 6-5 (final boss) + code:006D:15 + +cartridge sha256:21c51dc47a458a7de66544533d56eb9a69de0190d012b1645699e816d2cb5008 + title:Ninja Gaiden II - The Dark Sword of Chaos (USA) + cheat + description:Invincibility + code:SZUGKGAI + cheat + description:Invincibility (alt) + code:OPOKUXUG + cheat + description:Infinite health + code:EANGKGSA + cheat + description:Infinite health (alt) + code:SZNGKGSA + cheat + description:Infinite Ninja power + code:XXEOSZVZ+LOEOVXIY+PUOOSXLK + cheat + description:Infinite time + code:SXVKLTVG + cheat + description:Infinite lives + code:SXXGXAVG + cheat + description:Hit anywhere + code:AAVKXZUI+AEEGOXKL+AEOGXXIA+ENOKKZEL + cheat + description:Multi-jump + code:EASGAPAP+GZSGYPEI+LPKKTOYP+LPSGZPTE+SZESEOSE+SZKKIPEY+SZNSXOSE+VXSSIYVA + cheat + description:Half-energy from medicine + code:LEUOSATA + cheat + description:Double energy from medicine + code:GEUOSATE + cheat + description:Never lose Ninja power item + code:GXKKUIVA + cheat + description:Fast running Ryu + code:ZEXGYAPA+SNEKYEVN + cheat + description:Mega-fast running Ryu + code:LEXGYAPA+KNEKYEVN + cheat + description:Half-energy from Blue Ninja power + code:IAUONEZA+IAKOOEZA + cheat + description:Double energy from Blue Ninja power + code:GPUONEZA+GPKOOEZA + cheat + description:Double maximum Ninja power from scroll + code:GOEPOEZA+ZEOOEAPA + cheat + description:All powers use up only 5 points + code:SVOPXXSN+SVOOKXSN+SVXOXXSN + cheat + description:Less enemies + code:AAZVYL + cheat + description:Start every life with two shadow ninjas + code:YAOIYOPE + cheat + description:Start with 1 life + code:AEKGVTZA + cheat + description:Start with 6 lives + code:IEKGVTZA+SEKKKTSP + cheat + description:Start with 9 lives + code:AEKGVTZE+SEKKKTSP + cheat + description:Invincibility (alt) + code:0068:09 + cheat + description:Infinite health (alt) + code:0080:16 + cheat + description:Infinite lives (alt) + code:00A5:03 + cheat + description:Infinite time (alt) + code:00AB:04+00B1:F4 + +cartridge sha256:ba5968f14a02f1adf8a6144fcf9c4acde80bce8a3e01bae54b555f258540dd4b + title:Ninja Gaiden III - The Ancient Ship of Doom (USA) + cheat + description:Invincibility + code:AEVPNYLA + cheat + description:Infinite lives + code:SXEKVLVG + cheat + description:Infinite health + code:SZEXILSA + cheat + description:Infinite time (timer will still countdown) + code:SZVZIIVG + cheat + description:Multi-jump and infinite time + code:ZASXPIIE+AENXOAGP+AZSXGIZL+EPSXZSUA+GXUPZLEL+LASXLIEI+LPSXASNL+OZSXTSNK+SZNXIIVG+XISXIIVK + cheat + description:Less time + code:VPKGXKXY + cheat + description:One hit kills + code:AEKXTEYA + cheat + description:Sword hits several areas of the screen at once (sword upgrade negates the effect) + code:YYXKEGAO+YYXKKGYE + cheat + description:No power required for Windmill Throwing Star + code:AESPKYPA+AEKOXNZA + cheat + description:No power required for Fire Wheel Art + code:AEKOUNAA+AESPENAA + cheat + description:No power required for Invincible Fire Wheel + code:AEKOVYGP+AESOEYZA + cheat + description:No power required for Fire Dragon Balls + code:AEKOKNAA+AESPONAA + cheat + description:No power required for Vacuum Wave Art + code:AEKOSNZA+AESPNYPA + cheat + description:Start with upgraded sword + code:PAXGKGAA+APXKEGAO+APXKKGYA + cheat + description:Invincibility (alt) + code:00AD:14 + cheat + description:Infinite health (alt) + code:00A7:0A + +cartridge sha256:648cf7ac553517573cc9b3955ab50566a91974b2348154910bfa53ef15d55b56 + title:Ninja Jajamaru - Ginga Daisakusen (Japan) + cheat + description:Invincibility + code:SZNPGTAX + cheat + description:Infinite lives + code:SIVOGKVS + +cartridge sha256:622c62d48aa244fb2427ce8d0cf45e5fc57d94ad82e47a3b5b45a0dd643c9cd7 + title:Ninja Kid (USA) + cheat + description:Infinite Feathers + code:SZOZUPVG + cheat + description:Infinite Stars + code:SZXXITVG + cheat + description:Infinite Boomerangs + code:SXNOGGVG + cheat + description:Infinite Fireflames + code:SXUZZYVG + cheat + description:More Invincibility time + code:AZEILNYE + cheat + description:Less Invincibility time + code:YAEILNYA + cheat + description:1 Feather on pick-up + code:PAXSXALA + cheat + description:6 Feathers on pick-up + code:TAXSXALA + cheat + description:10 Stars on pick-up + code:ZAXSUAGO + cheat + description:40 Stars on pick-up + code:AZXSUAGO + cheat + description:1 Boomerang on pick-up + code:ZAXSKAGA + cheat + description:10 Fireflames on pick-up + code:ZAXSSAGO + cheat + description:40 Fireflames on pick-up + code:AZXSSAGO + cheat + description:Start with 1 life + code:AAVEZAZA + cheat + description:Start with 6 lives + code:IAVEZAZA + cheat + description:Start with 9 lives + code:AAVEZAZE + +cartridge sha256:b0e4d88db0b21db4a84e3c21d51898c686e9031dc138b2939877ecad20dd2350 + title:Nintendo World Cup (USA) + cheat + description:1 minute in tournament mode + code:AAUVKZLA + cheat + description:6 minutes in tournament mode + code:IAUVKZLA + cheat + description:9 minutes in tournament mode + code:AAUVKZLE + cheat + description:6 minutes in match mode + code:IAKTXXPA + cheat + description:3 minutes in match mode + code:ZAKTXXPA + cheat + description:1 minutes in match mode + code:AAKTXXPA + cheat + description:Faster players + code:PEXLUIAA + cheat + description:More powerful 'normal' shots + code:AYXXNXAL + +cartridge sha256:6157c99fe7a214025c65fd3649e4afe9cd2d38c333e65af028b935e49fbeb500 + title:Noah's Ark (Europe) + cheat + description:Invincibility + code:SZUUNAAX + cheat + description:Invincible against spikes + code:SXEKUYAX + cheat + description:Infinite lives + code:SKNEGUVK+SKSAVEVK + cheat + description:Infinite health + code:SZKUUGSA + cheat + description:Infinite time + code:SGEVZOVK + +cartridge sha256:55c2d10ae1b034b39533f780f6205f736735df1954c0eca6d147cfc13a224f82 + title:North and South (USA) + cheat + description:Cannon has 5 shots + code:IEUATOPA + cheat + description:Cannon has 15 shots + code:YEUATOPE + cheat + description:Cannon has infinite shots + code:SZXPYUVS + cheat + description:No cannons allowed + code:GXXATOSO + cheat + description:Only 2 daggers in the fortress + code:ZAUAGPGA + cheat + description:Infinite daggers in the fortress + code:GXXPLKVS + cheat + description:2 men in the fortress + code:ZAUETOZA + cheat + description:5 men in the fortress + code:IAUETOZA + cheat + description:2 men on the train + code:ZASAGOZA + cheat + description:5 men on the train + code:IASAGOZA + +cartridge sha256:106a9cd2acc3373bf2fae05158bdf7587d5f645402ba8073aaee65cb8b7b11cd + title:Operation Secret Storm (USA) (Unl) + cheat + description:Infinite lives + code:OLUVZUOO + cheat + description:Infinite Gun ammo + code:SLKVYSOO + cheat + description:Infinite health + code:0520:17 + +cartridge sha256:36666e3314ee9e0a340b04ea8427aaefb6df8937425a016e78c26fb1fa77b017 + title:Operation Wolf (USA) (Rev 0A) + cheat + description:Infinite continues + code:IEVUNSPA + cheat + description:Never die + code:AESSLZTL + cheat + description:Infinite magazines + code:AAVSIIPA + cheat + description:Infinite grenades + code:AAEIATPA + cheat + description:Double bullets in each magazine + code:GANIYIZA + cheat + description:Heal completely between levels + code:NNESZALE + cheat + description:Grenades inflict double damage + code:GANULZZA + cheat + description:Super power drinks + code:ZAELGPIE + cheat + description:Increase magazines + code:PEVKVYYE+PAVSIIIE + cheat + description:Increase grenades + code:PENGXYIE+PAVSIILE + cheat + description:Start on mission 2 + code:PESZIGAA + cheat + description:Start on mission 3 + code:ZESZIGAA + cheat + description:Start on mission 4 + code:LESZIGAA + cheat + description:Start on mission 5 + code:GESZIGAA + cheat + description:Start on mission 6 + code:IESZIGAA + +cartridge sha256:4d2b5339703d2300539348e3aad055fd00828afcbd9f3a97565e37725221fc0a + title:Orb 3D (USA) + cheat + description:Infinite fuel + code:03FD:50 + cheat + description:Start on level 10 + code:03E2:09 + cheat + description:Start on level 15 + code:03E2:13 + cheat + description:Start on level 30 + code:03E2:1D + +cartridge sha256:d50327afa539f4a5ccfd6e10f685326eb0f01915ccf305f752deae2bf17385a6 + title:Over Horizon (Europe) + cheat + description:Invincibility (blinking) + code:SXNIETVG + cheat + description:Infinite lives + code:SXULESVK + cheat + description:Enable alternate graphics + code:PEEIITAA + +cartridge sha256:b3a798ab7f2f237c7bd3c3e8b36cc752d850d10a8597e43771c82dcd654d5dae + title:Overlord (USA) + cheat + description:Food not decreased + code:GPEAPOIE + cheat + description:Hover tanks never decrease in battle + code:SXXUKVVK + cheat + description:Ballistic Missiles never decrease in battle + code:SZKOPOVK + cheat + description:Homing Missiles never decrease in battle + code:SZSPGOVK + cheat + description:Enemy starts with 0 Missiles + code:NZVUKNNP + cheat + description:Constantly get 9999999 cash on all planets with 1% or higher tax + code:ESKALPEL + cheat + description:View a planet's stats for high food + code:YYXLIYAE+OPXUPNOU + cheat + description:View a planet's stats for high people + code:YYOLEAAE+OPOLKEOU + cheat + description:View a planet's stats for high energy + code:YNKUYYAE+OOSLLNOU + cheat + description:View a planet's stats for high fuel + code:YNEUTYAE+OOOLZNOU + +cartridge sha256:ae2dddda1f90b8f8e3a990a2247ab4e373f69e6599f4e63f531d3a541b54bd85 + title:P.O.W. - Prisoners of War (USA) + cheat + description:Invincibility + code:ATVUUZSA + cheat + description:Infinite lives + code:AENSLPPA + cheat + description:Infinite bullets + code:AAVGOTPA + cheat + description:One hit kills + code:OLEUSOSU + cheat + description:Take less damage when hit from behind + code:STOLOUON + cheat + description:Keep weapons after dying + code:GZUUNUSE+GZSLOSSE + cheat + description:Start with half health + code:APKGPLAZ+APESYZAZ + cheat + description:Start with 1 life + code:AEUEIZZA + cheat + description:Start with 6 lives + code:IEUEIZZA + cheat + description:Start with 9 lives + code:AEUEIZZE + cheat + description:Start with 99 lives + code:LVUEIZZA + cheat + description:Have infinite Grenades, Brass Knuckles, Armor Vest + code:0438:F9 + cheat + description:Have infinite Knives, Brass Knuckles, Armor Vest + code:0438:E5 + cheat + description:Have infinite Gun, Brass Knuckles, Armor Vest + code:0438:DB + cheat + description:Start on stage 2 (disable after stage begins) + code:0047:01 + cheat + description:Start on stage 3 (disable after stage begins) + code:0047:02 + cheat + description:Start on stage 4 (disable after stage begins) + code:0047:03 + cheat + description:Start on stage 5 (disable after stage begins) + code:0047:04 + cheat + description:Start on stage 6 (disable after stage begins) + code:0047:05 + +cartridge sha256:fa12a61eb787bf8346a81e5b6eaede75238a1735db24a6f4df51ac3a6b499f18 + title:Pac-Man (USA) (Namco) + cheat + description:Invincibility + code:GZEIYLEY + cheat + description:Get 8000+ points for eating ghosts + code:EZOSLLKZ+TAOSGUOI+SZXIYLVT + cheat + description:Power Pill effect always active + code:0088:0F + cheat + description:Infinite lives + code:0067:03 + +cartridge sha256:1e60a181e1f89f2249a3e0d44a7765c2cdd9e0446f1671c63bf2c6f6df562d4c + title:Pac-Man (USA) (Tengen) + cheat + description:Invincibility + code:GXKITZEY + cheat + description:Walk through walls + code:AAVSYUAP+AIUSZGEI+AINILGEY+AYVSZGEY + cheat + description:Get 8000+ points for eating ghosts + code:EXSSZZKZ+TESSLXOI+SXVITZVT + cheat + description:Power pills last longer + code:AYVITOGL + cheat + description:Power pills last extra long + code:NYVITOGU + cheat + description:Power pills don't last as long + code:AZVITOGL + cheat + description:Power pills don't work + code:ATXTZASZ + cheat + description:Only 3 ghosts are edible + code:IAXVYEYE + cheat + description:Only 2 ghosts are edible + code:PAXVYEYE + cheat + description:Pac-Man moves manually + code:NZSSLLIU + cheat + description:Power Pill effect always active + code:0088:15 + cheat + description:Infinite lives + code:0067:03 + +cartridge sha256:25506ac6d6413a73249d3ce6a4ecc40048982596e01d778eddb71baca084efa6 + title:Pac-Man (USA) (Tengen) (Unl) + cheat + description:Invincibility + code:GXKITZEY + cheat + description:Get 8000+ points for eating ghosts + code:EXSSZZKZ+TESSLXOI+SXVITZVT + cheat + description:Power pills last longer + code:AYVITOGL + cheat + description:Power pills last extra long + code:NYVITOGU + cheat + description:Power pills don't last as long + code:AZVITOGL + cheat + description:Power pills don't work + code:ATXTZASZ + cheat + description:Only 3 ghosts are edible + code:IAXVYEYE + cheat + description:Only 2 ghosts are edible + code:PAXVYEYE + cheat + description:Power Pill effect always active + code:0088:15 + cheat + description:Infinite lives + code:0067:03 + +cartridge sha256:acc561f57cfd0490fdce649deb16fa9df309bba1695608213a0ff8066d662492 + title:Pac-Mania (USA) (Unl) + cheat + description:Infinite lives + code:SZKIOPVG + cheat + description:Trapped ghosts + code:ANTGUN + cheat + description:Go through ghosts + code:SOLIVA + cheat + description:Ghosts worth 3200 points + code:PEASNA + +cartridge sha256:6c47c73eb510fb0f71eeb2a3f5cca7c25eca8678ffe060aa17df6534dbd10ef1 + title:Panic Restaurant (USA) + cheat + description:Invincibility + code:ENUPPAEI + cheat + description:Infinite health - except when you fall on spikes + code:OXVPPAVK + cheat + description:Infinite health (alt) + code:SXVPPAVG + cheat + description:Infinite time + code:OZVKGZVK + cheat + description:Infinite time (alt) + code:SGVKGZVG + cheat + description:Infinite lives + code:SAOSAGVG + cheat + description:Infinite lives (alt) + code:SZOSAGVG + cheat + description:Start with 4 hearts + code:GASYZGZA + cheat + description:Start with 2 lives + code:PAOZNIZA + cheat + description:Start with 5 lives + code:IAOZNIZA + cheat + description:Start with 6 hearts (heart meter will be distorted) + code:TASYZGZA + cheat + description:Start with 10 hearts (heart meter will be distorted) + code:ZASYZGZE + cheat + description:Start with 10 lives (meter will display 9) + code:ZAOZNIZE + cheat + description:Start with 15 lives (meter will display 9) + code:YAOZNIZE + cheat + description:Start with 80 on timer (1st level only) + code:AIVYGGLT+AIVKXYLT + cheat + description:Start with 70 on timer (1st level only) + code:TGVYGGLT+TGVKXYLT + cheat + description:Start with 60 on timer (1st level only) + code:GLVYGGLV+GLVKXYLV + +cartridge sha256:73f0f7b9150fb080541426cedc87bf528c63393e6112812112e8c1339d9bfbf5 + title:Panda Prince, The (Shin-Shin) (Unl) + cheat + description:Infinite lives + code:SXOOLYSA + +cartridge sha256:f1c9c4723190d6be5f1f683ad5fd8cc123abd70d42f486c175a25f1237db6199 + title:Paperboy (USA) + cheat + description:Invincibility against moving objects + code:APNEOZEO+ATNEXZGA + cheat + description:Invincibility against non-moving objects + code:AAKPSGTA + cheat + description:Infinite lives + code:SXSEVZVG + cheat + description:Infinite papers + code:OZNOKAVK + cheat + description:Infinite time in training course + code:SZXOUESE + cheat + description:Gain 20 papers on pick-up + code:GPUONUZA + cheat + description:Start with 1 life + code:PAUOEIGA + cheat + description:Start with 6 lives + code:TAUOEIGA + cheat + description:Start with 20 papers + code:GOXAUOZA + +cartridge sha256:dec09033f68850bd25cf3e8bf0e05a44970301c4aaac2cbc27b8f9e96392b409 + title:Paperboy 2 (USA) + cheat + description:Infinite lives + code:AAKEZLPA + cheat + description:Infinite papers + code:AEVPNLPA + cheat + description:5 papers on pick-up + code:IEOAEOZA + cheat + description:15 papers on pick-up + code:YEOAEOZE + cheat + description:20 papers on pick-up + code:GOOAEOZA + cheat + description:Start with 1 life - Paperboy only + code:PEOUYGIA + cheat + description:Start with 3 lives - Paperboy only + code:LEOUYGIA + cheat + description:Start with 10 lives - Paperboy only + code:ZEOUYGIE + cheat + description:Start with 15 papers + code:YAELGVZE + cheat + description:Start with 20 papers + code:GPELGVZA + +cartridge sha256:25ae9f90412612715a254973006f0056016a840efc8af1fbdb6fc2eb7cd5eb7c + title:Parasol Stars - Rainbow Islands II (Europe) + cheat + description:Invincibility + code:005C:03 + cheat + description:Automatically finish levels + code:0320:00+0321:00+0322:00+0323:00+0324:00+0325:00+0326:00+0327:00 + cheat + description:Make the Miracle Icon appear (enable then disable) + code:04FB:01 + +cartridge sha256:f0d89b53126513e1df56b46bae3a43b4a4b87543d48974c9087ba94737249801 + title:Parodius (Europe) + cheat + description:Enemies die automatically + code:008B:02 + cheat + description:Infinite Shield on pick-up + code:64D0:0F + +cartridge sha256:f1762c9f40e6e45a123b73a035841768e0132fa82c92f9d066a8718a7f99b6cc + title:Pesterminator (USA) (Unl) + cheat + description:Infinite health + code:VVOSPNVG + cheat + description:Infinite lives + code:VXNIIEVK + +cartridge sha256:1c598fe0b58811b1bedfc6f2cda05f0960b4a6e2770c8a2f73cd6da370ed2448 + title:Phantom Fighter (USA) + cheat + description:Infinite health + code:SXSZLUSE + cheat + description:Take less damage when attacked + code:OVSZPLSV+PESZZLAA + cheat + description:Start with Sacred Sword + code:VTVKEGSA+KAVKOGNA + cheat + description:Start with Bell + code:VTVKEGSA+SAVKOGNA + cheat + description:Start with Tonten + code:VTVKEGSA+UAVKOGNA + cheat + description:Start with Talisman + code:VTVKEGSA+XAVKOGNA + cheat + description:Start with 3 Scrolls + code:LASKNGAA+VAVKOGNA + cheat + description:Start with 6 Scrolls + code:TASKNGAA+VAVKOGNA + cheat + description:Infinite HP + code:0408:C8 + cheat + description:Max HP + code:040A:C8 + cheat + description:One hit kills + code:0448:01 + cheat + description:Have 99 Scrolls + code:0086:63 + cheat + description:Have 3 Crystal Balls + code:0087:03 + cheat + description:Have strongest punch + code:0076:03 + cheat + description:Have strongest kick + code:0077:03 + cheat + description:Have highest jump + code:0078:03 + cheat + description:Have best Tiger move + code:0079:03 + cheat + description:Have best Mirage move + code:007A:03 + cheat + description:Have Talisman + code:0082:01 + cheat + description:Have Tonten + code:0083:01 + cheat + description:Have Sacred Sword + code:0084:01 + cheat + description:Have Bell + code:0085:01 + +cartridge sha256:c701cffa5315b4375c0a71d2e7378137bcdeed0684f57bf7eb2fbed3b2c1b1da + title:Pictionary - The Game of Video Quick Draw (USA) + cheat + description:Infinite time + code:0084:20 + +cartridge sha256:f4ddb0f1a02f823ebed30b55547344de3c8fb9d87254ff993584373ecadd9141 + title:Pin Bot (USA) + cheat + description:Infinite balls + code:OZVVYZVV + cheat + description:Start with only 1 ball + code:PANTGZLA + cheat + description:Start with 6 balls + code:TANTGZLA + cheat + description:Start with 9 balls + code:PANTGZLE + +cartridge sha256:910ba4505b46a99b3779d84fd22ba8b18f3a649b0c1a11706c4609d06ce0bc18 + title:Pinball (World) + cheat + description:Infinite balls + code:SUXKLEVS + cheat + description:Start with lots of balls + code:YZSGPALE + cheat + description:Start with 1 ball + code:PASGPALA + cheat + description:Start with 6 balls + code:TASGPALA + cheat + description:Start with 9 balls + code:PASGPALE + +cartridge sha256:7dd47bac196af9874181e86f64402035e255814739828d5d00c03bac8689d40a + title:Pipe 5 (Asia) (Unl) + cheat + description:Infinite time (disable to finish round) + code:0080:09 + cheat + description:1 distance needed + code:008E:01 + cheat + description:Automatically finish round + code:008E:00 + +cartridge sha256:a57f873ccb2c8842e9ef1a8380c87026a8ef0c6649f1cc02ce0743fae61ea120 + title:Pipe Dream (USA) + cheat + description:Infinite wrenches + code:SZKTPUVK + cheat + description:One-way pipes from level 1 + code:AAOGZZIA + cheat + description:One-way pipes from level 5 + code:IAOGAZLA + cheat + description:One-way pipes from level 10 + code:ZAOKPZLE + cheat + description:Tunnels galore + code:KEUAUVSE + cheat + description:Pumps instead of reservoirs + code:GPKIEGZP + cheat + description:Pumps before reservoirs + code:GPKIEGZP+ZPKINGGP + cheat + description:Start with 1 wrench + code:PAOALPLA + cheat + description:Start with 6 wrenches + code:TAOALPLA + cheat + description:Start with 9 wrenches + code:PAOALPLE + +cartridge sha256:ac1215af2a3315f8bbff01987f24a85e9c1fe984287c05fc21246b0a66fd5dfd + title:Platoon (USA) (Rev A) + cheat + description:Stage 1 - Infinite grenades + code:SXKOZPVG + cheat + description:Stage 1 - Start with double capacity magazine + code:SZSPYAVG + cheat + description:Stage 1 - Double hits + code:AEKESYGE + cheat + description:Stage 1 - Don't take damage + code:SXKAUYVT + cheat + description:Stage 2 - Don't take damage + code:SZVAXTVT + cheat + description:Stage 4 - Infinite time + code:SXKEUZVG + cheat + description:Stage 4 - Play with more time + code:IEVEOPLA + cheat + description:Stage 4 - Double hits + code:PAKOIPIE + cheat + description:Stage 4 - Halve hits + code:ZAKOIPIA + cheat + description:Stage 4 - Start with double ammo + code:GEXEUPTE + cheat + description:Start on stage 2 + code:GAKEAPIA + cheat + description:Start on stage 3 + code:LAEGGATA + +cartridge sha256:61ac77e84b4aa089115a682a2e8cfaa6811ba83b567ae1f13d8b644e0c42a2bf + title:Platoon (USA) + cheat + description:Stage 1 - Infinite grenades + code:SXKOZPVG + cheat + description:Stage 1 - Start with double capacity magazine + code:SZSPYAVG + cheat + description:Stage 1 - Double hits + code:AEKESYGE + cheat + description:Stage 1 - Don't take damage + code:SXKAUYVT + cheat + description:Stage 2 - Don't take damage + code:SZVAXTVT + cheat + description:Stage 4 - Infinite time + code:SXKEUZVG + cheat + description:Stage 4 - Play with more time + code:IEVEOPLA + cheat + description:Stage 4 - Double hits + code:PAKOIPIE + cheat + description:Stage 4 - Halve hits + code:ZAKOIPIA + cheat + description:Stage 4 - Start with double ammo + code:GEXEUPTE + cheat + description:Start on stage 2 + code:GAKEAPIA + cheat + description:Start on stage 3 + code:LAEGGATA + +cartridge sha256:97f56ee3bcb0542996401a65c63a0e91c1c9c71da07f0619975e910946f9540d + title:Popeye (World) (Rev A) + cheat + description:Invincibility against enemy + code:ATGIYP + cheat + description:Invincibility against shots + code:ATISTL + cheat + description:Start with 1 life + code:PAPKNA + cheat + description:Start with 6 lives + code:TAPKNA + cheat + description:Start with 9 lives + code:PAPKNE + +cartridge sha256:23e457d854d5ce2bb8b81cef9fbbff0164171505a4d2d9e28ecbc2d062c81517 + title:Popo Team (Asia) (Unl) + cheat + description:Invincibility + code:004F:01 + cheat + description:Infinite lives + code:003F:03 + cheat + description:Slower enemies + code:004D:01 + +cartridge sha256:4986c3862a04fcf5b22df58b1182ec2ad636e6083714ac7c069adc1639023ebf + title:Power Blade (USA) + cheat + description:Infinite health + code:OTKESZSV + cheat + description:Infinite lives + code:SZSIAAVG + cheat + description:Hit anywhere + code:AEOANGZZ+ENEEUGEP + cheat + description:Take minimum damage + code:SZKAKXOU + cheat + description:Mega-jump + code:AZXSAVAU + cheat + description:Don't lose boomerang strength when you die + code:GZUITAVG+GZVITASA + cheat + description:Don't lose multi-boomerangs when you die + code:GZUSGAVG+GZVSZASA + cheat + description:Press Start to finish the level (don't use on Protect level) + code:AEEIPPPE+AOEILOIK+AVEIGOOZ + cheat + description:Start a new game to view the ending + code:YANNLTZA + cheat + description:Start with 1 life + code:AAXYZYZA + cheat + description:Start with 6 lives + code:IAXYZYZA + cheat + description:Start with 9 lives + code:AAXYZYZE + cheat + description:Infinite health (alt) + code:04AB:12 + cheat + description:Infinite lives (alt) + code:0027:09 + cheat + description:Infinite time + code:0095:09+0096:99 + +cartridge sha256:6c462c3fa07aab70759376fe6b59e9c91e808f79fae2960f869bafc9cf20dca2 + title:Power Blade 2 (USA) + cheat + description:Infinite health - except for spikes + code:OVSLZLSV + cheat + description:Infinite lives + code:GZSILAVG + cheat + description:Infinite time + code:ATKKXZSZ + cheat + description:Infinite life tanks + code:GXEVXTVG + cheat + description:Infinite energy tanks + code:GZEIPLVG + cheat + description:Speed up timer + code:YPKGNXYU + cheat + description:Slow down timer + code:YYKGNXYU + cheat + description:Throw meter doesn't decrease when boomerang is thrown + code:SAKSZZSZ + cheat + description:Take minimal damage + code:OVSLZLSV+PESLLLAA + cheat + description:Maximum throwing ability on pick-up + code:OZVULSOK+SANLZIVT + cheat + description:Start a new game to view the ending + code:YAXTNTLA + cheat + description:Start with 1 life + code:AEKEPTZA + cheat + description:Start with 6 lives + code:IEKEPTZA + cheat + description:Start with 9 lives + code:AEKEPTZE + cheat + description:Infinite health + code:049A:12 + cheat + description:Infinite lives (alt) + code:009F:99 + cheat + description:Have max POW + code:0054:0F + cheat + description:Have max energy + code:00A0:12 + cheat + description:Have Dual Power-Blades + code:0099:01 + cheat + description:Have Red Power-Blades + code:00A2:01 + cheat + description:View ending + code:0018:07 + +cartridge sha256:ae360d56679f179109ca7d07ad8b4da644ad53a39ffe1d47c8db00648af4bdb0 + title:Power Punch II (USA) + cheat + description:Infinite health + code:SZEYXGSA + cheat + description:Infinite health (alt) + code:00CE:FF + cheat + description:Instant win + code:00CD:00 + cheat + description:Max Punch + code:00C3:FF + cheat + description:max Stamina + code:00C4:FF + +cartridge sha256:76cdd991b85e4a15c62275fe6b3ccd5132ee2d17e70fe4d2173b8ce5d1193ec0 + title:Predator (USA) + cheat + description:Invincibility (normal mode) + code:VASAOASA+OGKKNGVK + cheat + description:Infinite health (big mode) + code:VVVAXUVK + cheat + description:Infinite health in jungle mode + code:AVUGVGSA + cheat + description:Infinite lives in jungle mode + code:SZNGGXVK + cheat + description:Infinite lives in big mode + code:SXXGZOVK + cheat + description:Start with double lives + code:AAVKGPGE + cheat + description:Mega-jumps in jungle mode + code:AEOETOPE + cheat + description:Don't die if you fall down holes + code:NTEENEGE+ATOAEEOZ + cheat + description:Start each life with Laser Rifle + code:LASEOELA+XLSEUEVX + cheat + description:Invincibility + code:0010:02 + cheat + description:Infinite lives + code:0504:09 + +cartridge sha256:7b0899bfde9661d1af5c2d88c46a8a70f1623729bf52db654fb40cda4554820b + title:Prince of Persia (USA) + cheat + description:Infinite health + code:SLXAINSO + cheat + description:Infinite time + code:SZKLIXSE + cheat + description:Infinite health (except for deep sword hit or a long fall) (alt) + code:06CF:03 + cheat + description:Infinite time (alt) + code:04EF:80 + +cartridge sha256:99f3ca1657ad48f9a4f128dce3e0e4efd2c4fee413a120a462055801c9581ebd + title:Princess Tomato in Salad Kingdom (USA) + cheat + description:Infinite gold coins + code:03CB:09 + +cartridge sha256:3910ae7495a71e6a55f70ed31eb345d28d6e9d524fe88679719d831f8f2553ce + title:Pro Sport Hockey (USA) + cheat + description:P1 goals worth 2 + code:ZESUZYPA + cheat + description:P1 goals worth 3 + code:LESUZYPA + cheat + description:P1 goals worth 4 + code:GESUZYPA + cheat + description:P1 goals worth 5 + code:IESUZYPA + cheat + description:P1 goals worth 6 + code:TESUZYPA + cheat + description:P1 goals worth 7 + code:YESUZYPA + cheat + description:P1 goals worth 8 + code:AESUZYPE + cheat + description:P2 goals worth 2 + code:ZENLZYPA + cheat + description:P2 goals worth 3 + code:LENLZYPA + cheat + description:P2 goals worth 4 + code:GENLZYPA + cheat + description:P2 goals worth 5 + code:IENLZYPA + cheat + description:P2 goals worth 6 + code:TENLZYPA + cheat + description:P2 goals worth 7 + code:YENLZYPA + cheat + description:P2 goals worth 8 + code:AENLZYPE + cheat + description:P1 starts with 1 point + code:VVNPTOSE + cheat + description:P2 starts with 1 point + code:VVNOPOSE + cheat + description:P1 starts with 2 points + code:ZENPIPAA+VVNOZPNT + cheat + description:P1 starts with 4 points + code:GENPIPAA+VVNOZPNT + cheat + description:P1 starts with 6 points + code:TENPIPAA+VVNOZPNT + cheat + description:P1 starts with 8 points + code:AENPIPAE+VVNOZPNT + cheat + description:P1 starts with 10 points + code:ZENPIPAE+VVNOZPNT + cheat + description:P2 starts with 2 points + code:ZENPIPAA+NVNPYPVT + cheat + description:P2 starts with 4 points + code:GENPIPAA+NVNPYPVT + cheat + description:P2 starts with 6 points + code:TENPIPAA+NVNPYPVT + cheat + description:P2 starts with 8 points + code:AENPIPAE+NVNPYPVT + cheat + description:P2 starts with 10 points + code:ZENPIPAE+NVNPYPVT + +cartridge sha256:e144020f37416f80f1a0da47aa9b3fbda338c61fcd175e8b2dc98df181e24b85 + title:Pro Wrestling (USA) (Rev A) + cheat + description:Infinite health and time + code:NTSTIVLE+OZSTGTVS+SASTTTEY+YTSTYVZA + cheat + description:Only have 5 seconds to get back into ring + code:IEETTZGP + cheat + description:Only have 10 seconds to get back into ring + code:ZEETTZGO + cheat + description:Have 30 seconds to get back into ring + code:TOETTZGO + cheat + description:Rounds are only 1 minute + code:PEXIKYIA + cheat + description:Rounds are only 3 minutes + code:LEXIKYIA + cheat + description:Rounds are 8 minutes + code:AEXIKYIE + cheat + description:Rounds are 10 minutes + code:ZEXIKYIE + cheat + description:2-second pin count + code:ZAVVTGLA + cheat + description:5-second pin count + code:IAVVTGLA + cheat + description:7-second pin count + code:YAVVTGLA + cheat + description:Infinite time (minutes) + code:0087:09 + cheat + description:Infinite time (seconds) + code:0086:3B + cheat + description:Pin once to win match + code:0077:00 + +cartridge sha256:96dafa1208bda2eaa601d6855d86cf670556018c2859805cae51a88f83e66e9e + title:Pro Wrestling (USA) + cheat + description:Infinite health and time + code:NTSTIVLE+OZSTGTVS+SASTTTEY+YTSTYVZA + cheat + description:Only have 5 seconds to get back into ring + code:IEETTZGP + cheat + description:Only have 10 seconds to get back into ring + code:ZEETTZGO + cheat + description:Have 30 seconds to get back into ring + code:TOETTZGO + cheat + description:Rounds are only 1 minute + code:PEXIKYIA + cheat + description:Rounds are only 3 minutes + code:LEXIKYIA + cheat + description:Rounds are 8 minutes + code:AEXIKYIE + cheat + description:Rounds are 10 minutes + code:ZEXIKYIE + cheat + description:2-second pin count + code:ZAVVTGLA + cheat + description:5-second pin count + code:IAVVTGLA + cheat + description:7-second pin count + code:YAVVTGLA + cheat + description:Infinite time (minutes) + code:0087:09 + cheat + description:Infinite time (seconds) + code:0086:3B + cheat + description:Pin once to win match + code:0077:00 + +cartridge sha256:635271fe654636ec37c882f76c5f8cd39b7b3a476c9aa75cefb548d82de8f896 + title:Punch-Out!! (USA) + cheat + description:Infinite health + code:0391:60 + cheat + description:Infinite hearts + code:0326:42 + cheat + description:Infinite Stars + code:0342:04 + cheat + description:One-hit knockdowns + code:0398:01 + +cartridge sha256:ea81de1a6d901d8d1ad229a6d8d88edcc8e1aeeae6146aa4cd01eb0310eb44d5 + title:Punisher, The (USA) + cheat + description:Invincibility (blinking) + code:ESKTGGEY+EVKTTKXK + cheat + description:Infinite health + code:SZNZKOSE+SZUZPVSE+VZKZNOVE + cheat + description:Infinite Grenades + code:XTSVSNXK + cheat + description:Infinite bullets and Rockets + code:AESYAPPA + cheat + description:Never lose a life against normal enemy + code:XVOVGXXK + cheat + description:Never lose a life against end of level enemy + code:XVOEXOXK + cheat + description:Hit anywhere + code:AANZGXAZ+AAOXYXIA+AAXXAKPA+AAXXZPZL + cheat + description:Faster Punisher + code:GEUUYIZA + cheat + description:Stage scrolls 2x as fast + code:PANVGGAA + cheat + description:Stage scrolls 3x as fast + code:ZANVGGAA + cheat + description:Stage scrolls 4x as fast + code:LANVGGAA + cheat + description:150 Machine Gun bullets on pick-up + code:PEUYNLAA + cheat + description:150 Assault Rifle bullets on pick-up + code:PEUNXLAA + cheat + description:Less energy on pick-up + code:AAEUUPAO + cheat + description:More energy on pick-up + code:APEUUPAO + cheat + description:Start with 1 life + code:PEOTYTIA + cheat + description:Start with 10 lives + code:ZEOTYTIE + +cartridge sha256:691ef0807cacd7032c52ff65ab1718c28be45c7220afcc13f20c645dfb40d4ed + title:Puss n Boots - Pero's Great Adventure (USA) + cheat + description:Infinite health + code:SZNGOISA + cheat + description:Infinite lives + code:SZOKZZVG + cheat + description:Auto-fire and auto-jump + code:AAOVNENY + cheat + description:Mega-jump + code:AAXGNUPA + cheat + description:Start with less health + code:GOSTNUAU + cheat + description:Start with 1 life + code:PEOGZALA + cheat + description:Start with 6 lives + code:TEOGZALA + cheat + description:Start with 9 lives + code:PEOGZALE + cheat + description:Start on stage 1 + code:GAEGAIAA + cheat + description:Start on stage 2 + code:PAEGAIAE + cheat + description:Start on stage 3 + code:TAEGAIAE + cheat + description:Infinite health (alt) + code:0092:38 + cheat + description:Infinite lives (alt) + code:000A:09 + +cartridge sha256:0cf2fc17a59a0932ce43e6b2e9ea4e2570f03139784b5c9df429a499e734b92e + title:Puzznic (USA) + cheat + description:Slower timer + code:ITKIPXGL + cheat + description:Faster timer + code:TPKIPXGU + cheat + description:Start on level 2-1 + code:ZEUAIPAE + cheat + description:Start on level 3-1 + code:GOUAIPAA + cheat + description:Start on level 4-1 + code:TOUAIPAE + cheat + description:Start on level 5-1 + code:AXUAIPAE + cheat + description:Start on level 6-1 + code:ZUUAIPAA + cheat + description:Start on level 7-1 + code:GUUAIPAE + cheat + description:Start on level 8-1 + code:TKUAIPAA + cheat + description:Start on level 9-1 + code:ASUAIPAA + +cartridge sha256:5fa346174b6b5a9dc2b5fe113ef8d8ac013a32b26dde6d5dfc9ed631d5e9af25 + title:Q-bert (USA) + cheat + description:Infinite lives + code:SXSZGPVG + cheat + description:Start with 1 life + code:PEUOOGIA+PAXZLLIA + cheat + description:Start with 10 lives + code:ZAXZLLIE+ZEUOOGIE + cheat + description:Start on level 3 + code:AESPVGAE + cheat + description:Start on level 6 + code:GOSPVGAA + cheat + description:Start on level 9 + code:AXSPVGAA + cheat + description:Infinite lives - P1 + code:004C:63 + cheat + description:Start on level 1 round 2 + code:0049:01 + cheat + description:Start on level 1 round 3 + code:0049:02 + cheat + description:Start on level 1 round 4 + code:0049:03 + cheat + description:Start on level 2 round 1 + code:0049:04 + cheat + description:Start on level 2 round 2 + code:0049:05 + cheat + description:Start on level 2 round 3 + code:0049:06 + cheat + description:Start on level 2 round 4 + code:0049:07 + cheat + description:Start on level 3 round 1 + code:0049:08 + cheat + description:Start on level 3 round 2 + code:0049:09 + cheat + description:Start on level 3 round 3 + code:0049:0A + cheat + description:Start on level 3 round 4 + code:0049:0B + cheat + description:Start on level 4 round 1 + code:0049:0C + cheat + description:Start on level 4 round 2 + code:0049:0D + cheat + description:Start on level 4 round 3 + code:0049:0E + cheat + description:Start on level 4 round 4 + code:0049:0F + cheat + description:Start on level 5 round 1 + code:0049:10 + cheat + description:Start on level 5 round 2 + code:0049:11 + cheat + description:Start on level 5 round 3 + code:0049:12 + cheat + description:Start on level 5 round 4 + code:0049:13 + cheat + description:Start on level 6 round 1 + code:0049:14 + cheat + description:Start on level 6 round 2 + code:0049:15 + cheat + description:Start on level 6 round 3 + code:0049:16 + cheat + description:Start on level 6 round 4 + code:0049:17 + cheat + description:Start on level 7 round 1 + code:0049:18 + cheat + description:Start on level 7 round 2 + code:0049:19 + cheat + description:Start on level 7 round 3 + code:0049:1A + cheat + description:Start on level 7 round 4 + code:0049:1B + cheat + description:Start on level 8 round 1 + code:0049:1C + cheat + description:Start on level 8 round 2 + code:0049:1D + cheat + description:Start on level 8 round 3 + code:0049:1E + cheat + description:Start on level 8 round 4 + code:0049:1F + cheat + description:Start on level 9 round 1 + code:0049:20 + cheat + description:Start on level 9 round 2 + code:0049:21 + cheat + description:Start on level 9 round 3 + code:0049:22 + cheat + description:Start on level 9 round 4 + code:0049:23 + +cartridge sha256:882a02c538cb097531da74d0ad685f6896dcfb7fa9b1a0cd540b4274968a7c13 + title:Q Boy (Asia) (Unl) + cheat + description:Infinite lives + code:SZSAKNVK + cheat + description:Infinite life + code:SXNZXOVK + cheat + description:Invincibility after first hit + code:AVXPYIVG + cheat + description:Infinite Breath Power + code:SXEXVXVK+SXOZOXVK + cheat + description:Infinite Lift Power + code:SZXZXUVK+SZXZSUVK + +cartridge sha256:745050dec23a692e1e759eb3e291f58ad7739fadb3a1308ec8d60085fefaec69 + title:Qix (USA) + cheat + description:1 life - P1 + code:PEEAPZGA + cheat + description:1 life - P2 + code:PEEEAZGA + cheat + description:Start on Level 5 - 1P game + code:IANAZZPA + cheat + description:Start on Level 10 - 1P game + code:ZANAZZPE + cheat + description:Start on Level 20 - 1P game + code:GPNAZZPA + cheat + description:Start on Level 5 - 2P game + code:IEEEGZPA + cheat + description:Start on Level 10 - 2P game + code:ZEEEGZPE + cheat + description:Start on Level 20 - 2P game + code:GOEEGZPA + +cartridge sha256:5dcea6d649f5ab79cf43dde76b92fb53b056fe92c6b49fd41f5158d9af0e9c32 + title:Quattro Adventure (USA) (Unl) + cheat + description:Boomerang Kid - Infinite lives + code:SZOGXVVK + cheat + description:Boomerang Kid - Start with 6 lives + code:TAOGPTLA + cheat + description:Linus Spacehead - Increase oxygen + code:AZKKPNAP + cheat + description:Linus Spacehead - Never lose oxygen + code:AEULZIPA + cheat + description:Linus Spacehead - Never lose life in the water + code:SXEGLYVG + cheat + description:Linus Spacehead - Never lose life in the land + code:SZXIILVG + cheat + description:Linus Spacehead - Start with 9 lives + code:PEKGGLLE + cheat + description:Super Robin Hood - Invincibility + code:AVONISPG + cheat + description:Super Robin Hood - Infinite lives + code:SXNKZIVG + cheat + description:Super Robin Hood - 9 energy hearts, you may lose some hearts when you pick up new ones + code:PAEGLTLE + cheat + description:Super Robin Hood - Start with 1 life + code:PAVGILLA + cheat + description:Super Robin Hood - Start with 6 lives + code:TAVGILLA + cheat + description:Super Robin Hood - Start with 9 lives + code:PAVGILLE + cheat + description:Treasure Island Dizzy - Invincible Dizzy Starts you in the Island In The Sky, walk left to arrive at the original starting point - + code:PEXSZYAA + cheat + description:Treasure Island Dizzy - Walk backwards + code:OZNTKASX + cheat + description:Treasure Island Dizzy - Start with snorkel + code:PEUSYYAA + cheat + description:Treasure Island Dizzy - Start with axe + code:PEUSYYAA+PEKNIZZP + cheat + description:Treasure Island Dizzy - Start with dynamite + code:PEUSYYAA+ZEKNIZZP + cheat + description:Treasure Island Dizzy - Start with heavy weight + code:PEUSYYAA+IEKNIZZP + +cartridge sha256:a537916d210a97e41e669c77f3ebcccb681dc44db4d8b758c2109baf8590d918 + title:Quattro Arcade (USA) (Unl) + cheat + description:Go! Dizzy Go! - Always kill monsters + code:XVTISU+XVTIVU + cheat + description:Go! Dizzy Go! - Walk through walls + code:XVTILU + cheat + description:Go! Dizzy Go! - Start with 1 life + code:PAVGZILA + cheat + description:Go! Dizzy Go! - Start with 6 lives + code:TAVGZILA + cheat + description:Go! Dizzy Go! - Start with 9 lives + code:PAVGZILE + cheat + description:Go! Dizzy Go! - Start on world 1, stage 3 + code:ZEEKGIPA + cheat + description:Go! Dizzy Go! - Start on world 1, stage 5 + code:GEEKGIPA + cheat + description:Go! Dizzy Go! - Start on world 2, stage 2 + code:TEEKGIPA + cheat + description:Go! Dizzy Go! - Start on world 2, stage 4 + code:AEEKGIPE + cheat + description:Go! Dizzy Go! - Start on world 4, stage 2 + code:AOEKGIPA + cheat + description:Go! Dizzy Go! - Start on world 4, stage 4 + code:ZOEKGIPA + cheat + description:Go! Dizzy Go! - Start on world 5, stage 1 + code:GOEKGIPA + cheat + description:Go! Dizzy Go! - Start on world 5, stage 3 + code:TOEKGIPA + cheat + description:Go! Dizzy Go! - Start on world 5, stage 5 + code:AOEKGIPE + cheat + description:Sunt Buggies - Infinite lives + code:SXOXZEVK + cheat + description:Sunt Buggies - Start with 1 life + code:PAKVXGLA + cheat + description:Sunt Buggies - Start with 6 lives + code:TAKVXGLA + cheat + description:Sunt Buggies - Start with 9 lives + code:PAKVXGLE + cheat + description:F-16 Renegade - Start with 2 lives - 1P game + code:PEUGEALA + cheat + description:F-16 Renegade - Start with 7 lives - 1P game + code:TEUGEALA + cheat + description:F-16 Renegade - Start with 10 lives - 1P game + code:PEUGEALE + cheat + description:F-16 Renegade - Start on level 3 + code:LEUGSAPA+PEKGXAAA + cheat + description:F-16 Renegade - Start on level 5 + code:IEUGSAPA+ZEKGXAAA + cheat + description:F-16 Renegade - Start on level 7 + code:YEUGSAPA+LEKGXAAA + cheat + description:F-16 Renegade - Start on level 9 + code:PEUGSAPE+GEKGXAAA + cheat + description:C.J.'s Elephant Antics - Infinite lives + code:SUKTZUVS + cheat + description:C.J.'s Elephant Antics - Start in Switzerland + code:PAEYOAAA + cheat + description:C.J.'s Elephant Antics - Start in Egypt + code:ZAEYOAAA + cheat + description:C.J.'s Elephant Antics - Start in Africa + code:LAEYOAAA + cheat + description:C.J.'s Elephant Antics - Always run fast after losing all lives + code:PAONILAA + cheat + description:C.J.'s Elephant Antics - Super C.J. after losing all lives + code:YAONILAE + cheat + description:C.J.'s Elephant Antics - Start with 1 life + code:PASTSVPA + cheat + description:C.J.'s Elephant Antics - Start with 5 lives + code:IASTSVPA + cheat + description:C.J.'s Elephant Antics - Start with 15 lives + code:YASTSVPE + cheat + description:C.J.'s Elephant Antics - Start with 20 lives + code:GPSTSVPA + +cartridge sha256:67123fe28cf5fbadeafc77400a0812f0135ab36706ec7d1267f84931d044e71d + title:Quest of Ki, The (Japan) + cheat + description:Exit always open + code:0053:01 + +cartridge sha256:d4f1650059a011455577561ea607993a5046d452ba987b1c7381cad56550be0a + title:R.B.I. Baseball (USA) + cheat + description:Perfectly straight pitches - both players + code:EESLUZTL+OXSLXZPN + cheat + description:Super slow pitches - both players + code:AEXUKZTL+OXXUUZOU + cheat + description:Slow pitches - both players + code:LEXUKZTL+OXXUUZOU + cheat + description:Fast pitches - both players + code:OXXUUZOU+YEXUKZTL + cheat + description:Super fast pitches - both players + code:OXXUUZOU+YEXUKZTU + cheat + description:All missed pitches are strikes - both players + code:AOVLSLEI + +cartridge sha256:3f9e3d3b48a897d94003df004ab4b332d749f85ea5d0e1a1b29b6d4f5634049a + title:R.C. Pro-Am (USA) (Rev A) + cheat + description:Infinite continues + code:AAEIPPPA + cheat + description:Max turbo on first pick-up + code:GEUGAPPA + cheat + description:Max tires on first pick-up + code:GEKKGPPA + cheat + description:Max speed on first pick-up + code:GAVGIPPA + cheat + description:Double turbo on first pick-up + code:ZEUGAPPA + cheat + description:Double tires on first pick-up + code:ZEKKGPPA + cheat + description:Double speed on first pick-up + code:ZAVGIPPA + cheat + description:Computer cars go crazy + code:SXVLGZAK + cheat + description:Always win as 1st place + code:005C:00 + cheat + description:Auto race at 128 MPH (disable if you get stuck) + code:05DC:80 + cheat + description:Max Super Sticky Tires + code:0453:04 + cheat + description:Max Turbo Acceleration + code:0454:04 + cheat + description:Max higher top speed + code:0455:04 + cheat + description:Infinite ammo for weapons + code:0459:63 + cheat + description:Have Bombs + code:045A:01 + cheat + description:Have Missiles + code:045A:02 + cheat + description:Have pick-up truck as vehicle + code:03F9:00 + cheat + description:Have off-road vehicle as vehicle + code:03F9:01 + cheat + description:Have race car as vehicle + code:03F9:02 + cheat + description:NINTENDO already spelled out (enable then disable) + code:03F7:08 + cheat + description:Computer cars go crazy (alt) + code:B2E4:AD + +cartridge sha256:aec6beb5b7e4d291a2bef75cb6dc43dc4db34f0313d26a8582ddf61b5b6a67c5 + title:R.C. Pro-Am (USA) + cheat + description:Infinite continues + code:AASIUAPA + cheat + description:Max turbo on first pick-up + code:GAOGOAPA + cheat + description:Max tires on first pick-up + code:GAXKSAPA + cheat + description:Max speed on first pick-up + code:GEKGTYPA + cheat + description:Double turbo on first pick-up + code:ZAOGOAPA + cheat + description:Double tires on first pick-up + code:ZAXKSAPA + cheat + description:Double speed on first pick-up + code:ZEKGTYPA + cheat + description:Computer cars go crazy + code:SZKLOPAK + cheat + description:Always win as 1st place + code:005C:00 + cheat + description:Auto race at 128 MPH (disable if you get stuck) + code:05DC:80 + cheat + description:Max Super Sticky Tires + code:0453:04 + cheat + description:Max Turbo Acceleration + code:0454:04 + cheat + description:Max higher top speed + code:0455:04 + cheat + description:Infinite ammo for weapons + code:0459:63 + cheat + description:Have Bombs + code:045A:01 + cheat + description:Have Missiles + code:045A:02 + cheat + description:Have pick-up truck as vehicle + code:03F9:00 + cheat + description:Have off-road vehicle as vehicle + code:03F9:01 + cheat + description:Have race car as vehicle + code:03F9:02 + cheat + description:NINTENDO already spelled out (enable then disable) + code:03F7:08 + cheat + description:Computer cars go crazy (alt) + code:B2E4:AD + +cartridge sha256:730399227c1566636f2e3475c398924165b21d88fc3321f60b29f4e6321a3c9c + title:R.C. Pro-Am II (USA) + cheat + description:Infinite credits + code:SUEEGXVS + cheat + description:Infinite Lazers on purchase + code:SXKVLVVS + cheat + description:Infinite Bombs on purchase + code:SXSTZKVS + cheat + description:Infinite Freezes on purchase + code:SXOVGVVS + cheat + description:Infinite Buckshot on purchase + code:SZXVGSVS + cheat + description:Infinite Missiles on purchase + code:SZSTTSVS + cheat + description:Items in the Model Shop are free if you have enough money + code:ATUXYGSZ + cheat + description:Buckshot costs 10 instead of 2,000 + code:PEETEOEG + cheat + description:Mega Pulse costs 2,080 instead of 20,000 + code:AEEVUPYA + cheat + description:Scoopers costs 2,200 instead of 15,000 + code:AANTSPIA + cheat + description:Dynafit tires costs 2,320 instead of 10,000 + code:AANTUPLA + cheat + description:Mega Motor costs 1,360 instead of 50,000 + code:AAVVUPLP + cheat + description:Hyper Motor costs 1,840 instead of 30,000 + code:AAVVOOLA + cheat + description:Freeze costs 2,200 instead of 15,000 + code:AEEVOPIA + cheat + description:Lazer costs 1,200 instead of 14,000 + code:AEETNPIA + cheat + description:Bombs costs 1,760 instead of 12,000 + code:AEETSPGA + cheat + description:Nobbies costs 1,880 instead of 7,000 + code:AANTOPZA + cheat + description:Missile costs 2,320 instead of 10,000 + code:AEETUPLA + cheat + description:Nitro costs 10 instead of 1000 + code:PANVKPGT + cheat + description:Oil slicks costs 10 instead of 500 + code:PANVXPZL + cheat + description:Skinny tires costs 10 instead of 2,000 + code:PAVVVOEG + cheat + description:Gold Motor costs 10 instead of 16,000 + code:AAVTNPTA+PAVTVPAG + cheat + description:Start with 1 credit instead of 3 + code:AESOLAZA + cheat + description:Start with 5 credits + code:GESOLAZA + cheat + description:Start with 7 credits + code:TESOLAZA + cheat + description:Start with 9 credits + code:AESOLAZE + cheat + description:Start on Track 02 + code:PEOGNTAA + cheat + description:Start on Track 03 + code:ZEOGNTAA + cheat + description:Start on Track 04 + code:LEOGNTAA + cheat + description:Start on Track 05 + code:GEOGNTAA + cheat + description:Start on Track 06 + code:IEOGNTAA + cheat + description:Start on Track 07 + code:TEOGNTAA + cheat + description:Start on Track 08 + code:YEOGNTAA + cheat + description:Start on Track 09 + code:PEOGNTAE + cheat + description:Start on Track 10 + code:ZEOGNTAE + cheat + description:Start on Track 11 + code:LEOGNTAE + cheat + description:Start on Track 12 + code:GEOGNTAE + cheat + description:Start on Track 13 + code:IEOGNTAE + cheat + description:Start on Track 14 + code:TEOGNTAE + cheat + description:Start on Track 15 + code:YEOGNTAE + cheat + description:Start on Track 16 + code:AOOGNTAA + cheat + description:Start on Track 17 + code:ZOOGNTAA + cheat + description:Start on Track 18 + code:LOOGNTAA + cheat + description:Start on Track 19 + code:GOOGNTAA + cheat + description:Start on Track 20 + code:IOOGNTAA + cheat + description:Start on Track 21 + code:TOOGNTAA + cheat + description:Start on Track 22 + code:YOOGNTAA + cheat + description:Start on Track 23 + code:AOOGNTAE + cheat + description:Start on Track 24 + code:POOGNTAE + cheat + description:Start on Track 25 + code:LOOGNTAE + cheat + description:Start on Track 26 + code:GOOGNTAE + cheat + description:Start on Track 27 + code:IOOGNTAE + cheat + description:Start on Track 28 + code:TOOGNTAE + cheat + description:Start on Track 29 + code:YOOGNTAE + cheat + description:Start on first Tug-O-Truck Challenge + code:AEOGNTAE + cheat + description:Start on Drag Race + code:POOGNTAA + cheat + description:Start on second Tug-O-Truck Challenge + code:ZOOGNTAE + cheat + description:Infinite continues + code:0771:09 + cheat + description:Infinite time at continue screen + code:0431:63 + +cartridge sha256:5cb8d03a90732d01737a401e8dc87a3d594ab2f901970f309fe551c0013ac5da + title:Race America (USA) + cheat + description:Can't down shift + code:SGSUGLVI + cheat + description:Cars only have 4 gears + code:IAVUILYA+IAKXAIYA + cheat + description:Go super fast in 6th gear + code:OZNOAAEN+NYNOPAIE+SAXPGZVT + +cartridge sha256:2e14f4481b5b762ba1ff0e7a25b07f316f7bdef0574a1704856f92823874f4e6 + title:Rad Racer (USA) + cheat + description:Infinite time + code:NYZINV + cheat + description:Never crash from things outside of the road + code:AAKSYIPA + cheat + description:Less time to finish each stage + code:GZXIUVIZ + cheat + description:More time to finish each stage + code:GLXIUVIX + cheat + description:Turbo acceleration + code:ALXGAIAA + cheat + description:Super Turbo acceleration + code:YYUKGIAU + cheat + description:Ultra Turbo acceleration + code:PEEGPIAA + cheat + description:Start on stage 2 + code:PAXKPAAA+GXKGKTSA + cheat + description:Start on stage 3 + code:ZAXKPAAA+GXKGKTSA + cheat + description:Start on stage 4 + code:LAXKPAAA+GXKGKTSA + cheat + description:Start on stage 5 + code:GAXKPAAA+GXKGKTSA + cheat + description:Start on stage 6 + code:IAXKPAAA+GXKGKTSA + cheat + description:Start on stage 7 + code:TAXKPAAA+GXKGKTSA + cheat + description:Start on stage 8 + code:YAXKPAAA+GXKGKTSA + cheat + description:Start on stage 2 (alt) + code:00E5:01 + cheat + description:Start on stage 3 (alt) + code:00E5:02 + cheat + description:Start on stage 4 (alt) + code:00E5:03 + cheat + description:Start on stage 5 (alt) + code:00E5:04 + cheat + description:Start on stage 6 (alt) + code:00E5:05 + cheat + description:Start on stage 7 (alt) + code:00E5:06 + cheat + description:Start on stage 8 (alt) + code:00E5:07 + +cartridge sha256:bcc8a24ab99f85933ff2cd0787daab6093710ef04f95b4c7bec842961ee0e3ad + title:Rad Racer II (USA) + cheat + description:Instant Boost + code:005F:FF + cheat + description:Don't wipeout when you hit something + code:005B:00 + +cartridge sha256:879ada5f1aa0282d81f9f13e91de53e181ed1030242029fcce002dfb8847c0c9 + title:Radia Senki - Reimei Hen (Japan) + cheat + description:No random battles + code:SXUYSZSA + +cartridge sha256:5d9f7deb09c9de8725c293366c943e6fef0a505a72bb1bc92be7a7a055cde464 + title:Raf World (Japan) + cheat + description:Invincibility + code:PAEVXXPX+PAOVEXPX + cheat + description:Infinite energy + code:SZUVUZSA + cheat + description:Infinite weapons + code:SZUAUTSA + cheat + description:Infinite lives + code:SKNGYLVG + cheat + description:Double-jump + code:AVKEIOOZ + +cartridge sha256:d79be89ff83550ba185d19fb586d2b5f988ad6743125b5233ab3bfe2cb814c94 + title:Raid 2020 (USA) (Unl) + cheat + description:Infinite health + code:SXSSESVK+SZKSVSVK + cheat + description:Infinite lives + code:SXVSIVVK + +cartridge sha256:b7b5fdf2b31c4b8c5340f93f166fb56aecf598f7c43a24b4334502bb81065143 + title:Raid on Bungeling Bay (USA) + cheat + description:Take no damage from anything + code:SXVVPIAX + cheat + description:Infinite Bombs + code:SXSIASVK + cheat + description:Can only carry 5 Bombs + code:AZOIIEGX + cheat + description:Start with 9 lives + code:PENGZYIE + cheat + description:Start with 1 life + code:PENGZYIA + cheat + description:Start on round 3 + code:LEVKTYPA + cheat + description:Start on round 6 + code:TEVKTYPA + cheat + description:Start on round 9 + code:PEVKTYPE + +cartridge sha256:9866b51b16b503aa515967929060eb100ae4cbd851229a3125ecf3ee7c88346e + title:Rally Bike (USA) + cheat + description:Infinite gas + code:SIUKLUVV + cheat + description:Infinite lives - 1P game + code:SZEITKVV + cheat + description:Infinite lives - 2P game, both players + code:SZOSIKVN + cheat + description:Start with 1 life - 1P game + code:PAUIKTIA + cheat + description:Start with 10 lives - 1P game + code:ZAUIKTIE + cheat + description:Start with 1 life - 2P game, both players + code:PAUIKITA+ZAXSTGTA + cheat + description:Start with 10 lives - 2P game, both players + code:ZAUIKTIE+LAXSTGIE + +cartridge sha256:2596cf1e1a9b09dac24aeffea708807173ec81fa7093b2a729f1539aec3b5764 + title:Rambo (USA) (Rev A) + cheat + description:Invincibility + code:ATOSXISL + cheat + description:Infinite weapons + code:SXOVXKVS + cheat + description:Gain double amount on pick-up + code:GOXTZXZA + cheat + description:Gain maximum amount on pick-up + code:GNXTZXZA + cheat + description:Hit anywhere + code:AEVSNOZL + cheat + description:Start with 2 Medicine Bottles + code:ZEEEITIA + cheat + description:Start with 9 Medicine Bottles + code:ZVEEITIA + cheat + description:Start with Hand Grenades + code:IPNEITPP+IOEALTPP + cheat + description:Infinite health + code:010C:64 + cheat + description:Max EXP + code:010F:23 + cheat + description:Infinite Throwing Knives + code:011D:99 + cheat + description:Infinite Missiles type 1 + code:011E:99 + cheat + description:Infinite Missiles type 2 + code:011F:99 + cheat + description:Infinite Machine Gun + code:0120:99 + cheat + description:Infinite Grenades + code:0121:99 + cheat + description:Infinite Red Potions + code:0122:99 + +cartridge sha256:94e0d73bfaa7dca6d117d8d6f92637ace17816bb37807152baa8978396fe8d46 + title:Rambo (USA) + cheat + description:Invincibility + code:ATOSXISL + cheat + description:Infinite weapons + code:SXOVXKVS + cheat + description:Gain double amount on pick-up + code:GOXTZXZA + cheat + description:Gain maximum amount on pick-up + code:GNXTZXZA + cheat + description:Hit anywhere + code:AEVSNOZL + cheat + description:Start with 2 Medicine Bottles + code:ZEEEITIA + cheat + description:Start with 9 Medicine Bottles + code:ZVEEITIA + cheat + description:Start with hand grenades + code:IPNEITPP+IOEALTPP + cheat + description:Infinite health + code:010C:64 + cheat + description:Max EXP + code:010F:23 + cheat + description:Infinite Throwing Knives + code:011D:99 + cheat + description:Infinite Missiles type 1 + code:011E:99 + cheat + description:Infinite Missiles type 2 + code:011F:99 + cheat + description:Infinite Machine Gun + code:0120:99 + cheat + description:Infinite Grenades + code:0121:99 + cheat + description:Infinite Red Potions + code:0122:99 + +cartridge sha256:bbe150f50bd11f5aa4e3edab47541261c58ab9899b6d9329450b3c77df172823 + title:Rampage (USA) + cheat + description:No harm from attacks or bad food + code:GXXLALOP + cheat + description:No harm from falling + code:AEXLPGAP + cheat + description:No harm from water + code:AAOUOPPA+AASLSPPA + cheat + description:Buildings collapse automatically + code:ASUTPIEL + cheat + description:Buildings collapse faster + code:ASSZGTEY+IOOZUXIA + cheat + description:One hit to destroy buildings + code:EEKXYPIA + cheat + description:More health - P1 + code:NYSGLUYN + cheat + description:More health - P2 + code:NYVKTUYN + cheat + description:Less health - P1 + code:YLSGLUYN + cheat + description:Less health - P2 + code:YLVKTUYN + cheat + description:More health after continue - both players + code:NNNGKNYN + cheat + description:Less health after continue - both players + code:YUNGKNYN + cheat + description:More damage done from falling + code:AXXLPGAP + cheat + description:Double health from food + code:GEULLLIA + cheat + description:Half health from food + code:AEULLLIA+ZKULTUZE + +cartridge sha256:501e921616931e4796c44b1e80c7112c881eb1e9a3190d0e6a3b4b199ee368e3 + title:Ren & Stimpy Show, The - Buckeroo$! (USA) + cheat + description:Infinite health + code:NYOYXLYE + cheat + description:Infinite lives + code:NYUVOZTE + cheat + description:Infinite collectibles + code:OUEAXXOO + cheat + description:Shorter invincibility after getting hit + code:YPEYOUGU + cheat + description:Longer invincibility after getting hit + code:ITEYOUGL + cheat + description:2 custard pies on pick-up + code:ZAXNPZIA + cheat + description:9 custard pies on pick-up + code:PAXNPZIE + cheat + description:Start with $11 instead of 0 + code:VNXELSSO + cheat + description:Start with 2 lives + code:PEUAPZLA + cheat + description:Start with 6 lives + code:IEUAPZLA + cheat + description:Start with 8 lives + code:YEUAPZLA + cheat + description:Start with 10 lives + code:PEUAPZLE + cheat + description:Start on Rescue the Maiden level + code:OZEEPYES+PAEEZYZZ + cheat + description:Start on Out West level + code:OZEEPYES+PAEEZYZZ+SAEELNVV + cheat + description:Start on Robin Hoek level + code:OZEEPYES+ZAEEZYZZ+SAEELNVV + +cartridge sha256:b4856061c9310015101c461aef744e9dcf3b158bd13d5d9cb4a76d3ca18a6864 + title:Renegade (USA) + cheat + description:Infinite lives + code:SXUIOTVG + cheat + description:Timer runs faster + code:TOSVOXTU + cheat + description:Timer runs slower + code:EXSVOXTL + cheat + description:Start with a super energy boost + code:AIUOZUAZ + cheat + description:Start with 1 life - both players + code:AEOSLYZA + cheat + description:Start with 6 lives - both players + code:IEOSLYZA + cheat + description:Start with 9 lives - both players + code:AEOSLYZE + cheat + description:Start on mission 2 + code:PEXSYYAA + cheat + description:Start on mission 3 + code:ZEXSYYAA + cheat + description:Start on mission 4 + code:LEXSYYAA + cheat + description:Infinite time + code:0472:59 + cheat + description:Enemies have no health + code:007E:00+007F:00+0080:00 + +cartridge sha256:f17df83a3e714c9f839dcd428d31a0b8b3cdb5fe1a78f24f43f158cb379720c1 + title:Ring King (USA) + cheat + description:Infinite power points - 1P game + code:GZEIPVVK + cheat + description:Don't lose stamina from fighting + code:GXKZXYOP + cheat + description:Rounds are 30 seconds + code:LEOSLYTA + cheat + description:Rounds are 90 seconds + code:PEOSLYTE + cheat + description:Players can't hurt each other + code:GXOZOIOP + cheat + description:No health - P2 / CPU + code:0319:00 + cheat + description:Infinite power (ten's digit) - P1 + code:038D:09 + cheat + description:Infinite power (one's digit) - P1 + code:038E:09 + cheat + description:Infinite time (ten's digit) + code:06E4:09 + cheat + description:Infinite time (one's digit) + code:06E5:09 + cheat + description:Max punch (ten's digit) - P1 + code:038F:09 + cheat + description:Max punch (one's digit) - P1 + code:0390:09 + cheat + description:Max speed (ten's digit) - P1 + code:0391:09 + cheat + description:Max speed (one's digit) - P1 + code:0392:09 + cheat + description:Max stamina (ten's digit) - P1 + code:0393:09 + cheat + description:Max stamina (one's digit) - P1 + code:0394:09 + cheat + description:No hits (hundred's digit) - P1 + code:06EC:00 + cheat + description:No hits (ten's digit) - P1 + code:06ED:00 + cheat + description:No hits (one's digit) - P1 + code:06EE:00 + +cartridge sha256:54cdc8b6fab804339c44601663585c8e7a8b01ef35b49754eb13a767b57c7d07 + title:River City Ransom (USA) + cheat + description:Infinite lives + code:SUNEUKSO + cheat + description:Start with max stats + code:LVSNAVYA + cheat + description:Infinite money + code:SUKOOXSO+SUSPEXSO+SUSPNXSO + cheat + description:Coins worth max amount of money + code:LZXTXGLP + cheat + description:Infinite Stamina + code:OOELVUOU+OXVUVUOV + cheat + description:Infinite Will Power + code:SLOXNNSO + cheat + description:Max Punch + code:YYVOIUYU + cheat + description:Max Kick + code:YYVOTUYU + cheat + description:Max Weapon + code:YYVOYUYU + cheat + description:Max Throw + code:YYNPAUYU + cheat + description:Max Agility + code:YYNPPUYU + cheat + description:Max Defense + code:YYNPZUYU + cheat + description:Max Strength + code:YYNPLUYU + cheat + description:Max Will Power + code:YYNPGUYU + cheat + description:Max Stamina + code:NYNPTUYN + cheat + description:View the credits + code:ENVYZZEI + cheat + description:Start with double every attribute + code:TOSNAVYE + cheat + description:Start with 127 of all stats + code:YNSNAVYE + cheat + description:Start with 99 Stamina + code:LVNYIVYL + cheat + description:Start with double money - P1 + code:AGENAYAZ + cheat + description:Start with double money - P2 + code:AGOYYYAZ + cheat + description:Start with $100 extra - P1 + code:PAENIYAA + cheat + description:Start with $100 extra - P2 + code:PAONGYAA + +cartridge sha256:46361c5b4007e6ef855430934b5a205aa19c885857a7eb31072646753d06e321 + title:RoadBlasters (USA) + cheat + description:Infinite credits + code:SZEIGEVK + cheat + description:Double credits + code:GAVLUTZA + cheat + description:Extend lifetime of UZ Cannon + code:PEEAEIIE + cheat + description:Extend lifetime of Nitro Injector + code:NNSEOIEE + cheat + description:Reduce lifetime of Nitro Injector + code:AKSEOIEA + cheat + description:Infinite Cruise missiles + code:SXVEKSVK+ETOENSTP + cheat + description:Infinite UZ Cannon + code:ATNEEISZ+LZOENSTO + cheat + description:Infinite Nitro Injectors + code:AVSEKSVG+SAOENSTO+GXKEOIEY + cheat + description:Infinite Electro Shield + code:SZSEKVVK+PIOENSTP+VAXAESSE + cheat + description:Infinite Fuel + code:0085:CF + cheat + description:Infinite Reserve Fuel + code:0086:6D + cheat + description:Max speed + code:009A:FF + +cartridge sha256:46a38baf9067869e8ecdf227c3cd33f14df20998d0d27e645e47f6c57fd9703d + title:Road Runner (USA) (Unl) + cheat + description:Infinite lives + code:SZOVUUVK + cheat + description:Never lose seed + code:XVUGAOEK+XVXTSUEK + cheat + description:Start with 1 life + code:AAEVTGIA + cheat + description:Start with 12 lives + code:LAEVTGIE + cheat + description:Start with 18 lives + code:PPEVTGIA + cheat + description:Start on level 5 + code:IAOTLGPA + cheat + description:Start on level 10 + code:ZAOTLGPE + cheat + description:Start on level 15 + code:YAOTLGPE + cheat + description:Start on level 20 + code:GPOTLGPA + cheat + description:Start on level 25 + code:PPOTLGPE + cheat + description:Start on level 30 + code:TPOTLGPE + +cartridge sha256:687e4129be3b8e224a9748cba9687b8c10e5feb234a727bdf2dcb8d3c8c47097 + title:Robin Hood - Prince of Thieves (USA) (Rev A) + cheat + description:Infinite HP for Robin in main combat + code:VAXEOLSA + cheat + description:Infinite HP for Robin in dueling combat + code:EYXAOPAL + cheat + description:Infinite Arrows + code:AASPIZPA + cheat + description:Bandages give more HP back + code:GOXLLNAA + cheat + description:Food gives more HP back - Except the Leg of meat + code:AOULIUAE + cheat + description:Infinite Arrows (alt) + code:0179:FF + cheat + description:Max Exp points + code:0604:FF + cheat + description:Max Level + code:0176:FF + cheat + description:Max Attack + code:0170:FF+0171:FF + cheat + description:Max Agility + code:016E:FF+016F:FF + cheat + description:Max Defense + code:0172:FF + cheat + description:Max Gold + code:0177:FF + cheat + description:Load zero + code:016C:00 + +cartridge sha256:bb0ed60fd8e83b56f23de16018696817cf8030b4898db6abe9dfc343e646e753 + title:Robin Hood - Prince of Thieves (USA) + cheat + description:Infinite HP for Robin in main combat + code:VAXEOLSA + cheat + description:Infinite HP for Robin in dueling combat + code:EYXAOPAL + cheat + description:Infinite Arrows + code:AASPIZPA + cheat + description:Bandages give more HP back + code:GOXLLNAA + cheat + description:Food gives more HP back - Except the Leg of meat + code:AOULIUAE + cheat + description:Infinite Arrows (alt) + code:0179:FF + cheat + description:Max Exp points + code:0604:FF + cheat + description:Max Level + code:0176:FF + cheat + description:Max Attack + code:0170:FF+0171:FF + cheat + description:Max Agility + code:016E:FF+016F:FF + cheat + description:Max Defense + code:0172:FF + cheat + description:Max Gold + code:0177:FF + cheat + description:Load zero + code:016C:00 + +cartridge sha256:5431ed49f22ee8188871be088da433c26b1ddeac972ef4b8f89df4eacd5e42c2 + title:Robo Warrior (USA) + cheat + description:No damage from bomb blast + code:GZUNYXTK + cheat + description:No damage from monsters and no power drain + code:GZNNIXTK + cheat + description:Infinite Barrier after pick-up + code:XTXGKPVV + cheat + description:Infinite Mega Bombs after pick-up + code:SUXSNIVI + cheat + description:Infinite Super Bombs + code:SZKTYPVG + cheat + description:5 Super Bombs on pick-up + code:IAVTPSZA + cheat + description:20 Super Bombs on pick-up + code:GPVTPSZA + cheat + description:Set firing range to 5 + code:IANGAPPA + cheat + description:Set firing range to 10 + code:ZANGAPPE + cheat + description:Start with 5 of everything + code:IEVKLPAA + cheat + description:Start with 10 of everything + code:ZEVKLPAE + cheat + description:Start with defense level at 5 + code:IEVGIPPA + cheat + description:Start with defense level at 8 + code:AEVGIPPE + +cartridge sha256:100c394264b40c17f635a6356c884135558bf2aee1a7f60c9ce43441e48a06cb + title:Robocco Wars (Japan) + cheat + description:Start on level 5 + code:GLUZOAAE + +cartridge sha256:d04b445ac57cccb3a31a3bf83d002dc9a9765f15313e96f67be077b6114d2411 + title:RoboCop (USA) + cheat + description:Invincibility + code:LLNTTZIU+SLXUYTAX + cheat + description:Infinite time + code:SXKXYIVT + cheat + description:Infinite ammunition + code:SGOTKLIA + cheat + description:No damage from touching enemies + code:SZKVOTSA + cheat + description:No damage from enemy bullets + code:SZVVVYSA + cheat + description:Bosses die automatically + code:AEOXIXLL + cheat + description:Can't harm civilian at the end of level 1 + code:SOKZLNSU + cheat + description:Triple normal power on power food pick-up + code:PAOYNILE + cheat + description:Triple normal time on battery pick-up + code:PAXNEILE + cheat + description:Max time on battery pick-up + code:TPXNEILA + cheat + description:Full power on power food pick-up + code:TPOYNILA + cheat + description:Use with COP Code 2 to start with machine gun and Cobra gun + code:YAXSAPPE + cheat + description:Press Start to finish the level (may cause graphical glitches in later levels) + code:YAXIGXTE + cheat + description:Start on level 2 + code:PAESZPAA+SAESLPSP+TTESGPSA + cheat + description:Start on level 3 + code:ZAESZPAA+SAESLPSP+TTESGPSA + cheat + description:Start on level 4 + code:LAESZPAA+SAESLPSP+TTESGPSA + cheat + description:Start on level 5 + code:GAESZPAA+SAESLPSP+TTESGPSA + cheat + description:Start on level 6 + code:IAESZPAA+SAESLPSP+TTESGPSA + cheat + description:Infinite health + code:006E:00 + cheat + description:Infinite time (alt) + code:0082:00 + +cartridge sha256:8ed3cb0046caecbefdc6c6b3ad8dae013442136f6a65c1a21b54586b0275e615 + title:RoboCop 2 (USA) (Rev A) + cheat + description:Invincibility + code:ENVEUYEI + cheat + description:Infinite health + code:AVKTPNOP + cheat + description:Infinite lives + code:SINKIPVI + cheat + description:Infinite time + code:SGETGYVG+SKNVGTVG + cheat + description:No enemies + code:EINAXLEY + cheat + description:Each N (Nuke) is worth 10 + code:AAEVKALA + cheat + description:Infinite health (alt) + code:0054:09+0055:09 + cheat + description:Infinite lives (alt) + code:0058:04 + cheat + description:Infinite time (alt) + code:0091:FF + cheat + description:Infinite N + code:0052:09+0053:09 + +cartridge sha256:b65361b45eef137a57152dd8f64531c26e34d728e72800d1bdf8e4be9bff49e7 + title:RoboCop 2 (USA) + cheat + description:Invincibility + code:ENVEUYEI + cheat + description:Infinite lives + code:SINKIPVI + cheat + description:No enemies + code:EINAXLEY + cheat + description:Infinite health + code:0054:09+0055:09 + cheat + description:Infinite lives (alt) + code:0058:04 + cheat + description:Infinite time + code:0091:FF + cheat + description:Infinite N + code:0052:09+0053:09 + +cartridge sha256:a0f18e729a7ee6be9035e9691f4bac32c1b202afcb44100479a431055b15eee6 + title:RoboCop 3 (USA) + cheat + description:Infinite efficiency + code:OXONLPSV+POONGPXV + cheat + description:Infinite efficiency (alt) + code:OUXYPOSO + cheat + description:One hit kills + code:GNUNAEKN + cheat + description:Hit anywhere + code:AEENAEUT + cheat + description:Lots of repair icons + code:VVKGLATE + cheat + description:Start with 2x health + code:ZLVGIXPP + cheat + description:Start with 1/2 health + code:GAVGIXPO + cheat + description:Infinite P + code:06A4:09 + cheat + description:Have main weapon - regular + code:001C:00 + cheat + description:Have main weapon - Rapid + code:001C:01 + cheat + description:have main weapon - 3-Way + code:001C:02 + cheat + description:have secondary weapon - Missiles + code:001D:00 + cheat + description:Have secondary weapon - Homing Missiles + code:001D:01 + cheat + description:Have secondary weapon - Bang + code:001D:02 + +cartridge sha256:92b1bde12ac860a385416b92529c15d149db54e53a56bd2a82ab97f517e67f86 + title:RoboCop versus The Terminator (USA) (Proto) + cheat + description:Infinite lives + code:SZKIZKSE + cheat + description:Infinite health + code:SZEVGOSE + cheat + description:Infinite health (alt) + code:04EE:0A + +cartridge sha256:d0e5899cf6b756d697be9ad6700d1f612b1604496374da9606478d5cdbceebf1 + title:Robodemons (USA) (Unl) + cheat + description:Infinite health + code:051B:14 + +cartridge sha256:e1a3d949b9bf258b4d2c92104cedd7957a311f142dc2cb32eb92ce559837377f + title:Rocketeer, The (USA) + cheat + description:Infinite health + code:GZSSINSV + cheat + description:Have all weapons with infinite ammo + code:AAVLKIIA + cheat + description:1/2 normal bullets on pick-up + code:IAOZZXZA + cheat + description:2x normal bullets on pick-up + code:GPOZZXZA + cheat + description:3x normal bullets on pick-up + code:TPOZZXZE + cheat + description:1/2 silver bullets on pick-up + code:ZAEZGZGO + cheat + description:2x silver bullets on pick-up + code:AZEZGZGO + cheat + description:3x silver bullets on pick-up + code:GLEZGZGO + cheat + description:Start with 1/2 health + code:GESLNKAA + cheat + description:Start with 2x health + code:AOSLNKAA + cheat + description:Start with 3x health + code:AOSLNKAE + cheat + description:Infinite health (alt) + code:05C5:0A + cheat + description:Infinite Rocket power + code:05B0:27 + cheat + description:Have all weapons with infinite ammo (alt) + code:05BF:63 + +cartridge sha256:a0d60fe16b09d2018e32c277f8a297adc71acdd9e851591625b2d460e96266c8 + title:Rocket Ranger (USA) + cheat + description:Double amount of Lunarium in storage + code:ZEOGSYPA + cheat + description:Triple amount of Lunarium in storage + code:LEOGSYPA + cheat + description:Lunarium level in backpack at 99 + code:LVOKXNGL + cheat + description:Never lose Lunarium in backpack + code:SZSGPUSE + cheat + description:Half amount of Lunarium in storage + code:AEOGSYPA+ZUOKNYAA + +cartridge sha256:683c49e4ea3f4b179065deccecd3e4a86a4e355e13924872571e7b7c79205d0c + title:Rockin' Kats (USA) + cheat + description:Invincibility + code:EIXVATEY + cheat + description:Infinite health + code:SXKVZVSE + cheat + description:Infinite lives + code:SKOKOSVK + cheat + description:Can select any item (you will not be able to see it) + code:AEOEYZOI + cheat + description:Can always select channel 5 + code:AEXEELAP + cheat + description:Can always buy items + code:OXEEOYSX + cheat + description:Infinite health (alt) + code:0423:0A + cheat + description:Infinite lives (alt) + code:041F:09 + cheat + description:Have all items + code:0105:0F + cheat + description:Infinite high cash + code:0104:0E + cheat + description:Channels 1-4 completed + code:0102:FF + +cartridge sha256:2bd31df34f925d030ceceb944c1ac973ccf892358de75c35fd77d61372d23a3b + title:Rock 'n' Ball (USA) + cheat + description:Infinite balls + code:SLNXYEVS + +cartridge sha256:9fdbaa2877363948b466a6e3e11a1bce02d2a6490cb90808be4d788fe4630eba + title:Rod Land (Europe) + cheat + description:Infinite lives + code:SLOPOOTS + cheat + description:Infinite time in extra game + code:SXOTAGVG + cheat + description:Start with invincibility + code:ESVSELEY + cheat + description:Start on scene 31 + code:TOSKYIAE + +cartridge sha256:1a35607e218d68106367e7b87735aa9f10bf330c3a71f607a21de2d7fc763ef8 + title:Roger Clemens' MVP Baseball (USA) + cheat + description:Infinite balls (balls are not called) + code:OONIALAA + cheat + description:Infinite balls and strikes + code:SLNALPVY + cheat + description:Strikes are not called when batter doesn't swing + code:OOVSLLPA + cheat + description:Strikes are not called when batter swings + code:GANAAPZA + cheat + description:2 strikes and you're out + code:ZANEAPLA+ZEOUYPLA+ZEVKGPLA + cheat + description:1 strike and you're out + code:PANEAPLA+PEOUYPLA+PEVKGPLA + cheat + description:1 ball for a walk + code:PENKLPGA + cheat + description:2 balls for a walk + code:ZENKLPGA + cheat + description:3 balls for walk + code:LENKLPGA + +cartridge sha256:942c802c34627c969c49dae94fb8b48c7b1e873a65803caad559324e2a54b4c8 + title:Rollerblade Racer (USA) + cheat + description:Infinite lives + code:OXVSAYVK + cheat + description:1 fall and you're dead + code:PEVIPYGA + cheat + description:6 falls and you're dead + code:TEVIPYGA + cheat + description:8 falls and you're dead + code:AEVIPYGE + cheat + description:Start on the City Street + code:ZAUKNZAA + cheat + description:Start with 1 life + code:PAUKUZLA + cheat + description:Start with 6 lives + code:TAUKUZLA + cheat + description:Start with 9 lives + code:PAUKUZLE + cheat + description:Start on Hit the Beach + code:GAUKNZAA + cheat + description:Start on Panic Park + code:TAUKNZAA + +cartridge sha256:7ddc56bf2b8d8f3f980837bbc48284fd7241e111a9f51599c6e358518d3469dc + title:Rollergames (USA) + cheat + description:Infinite lives + code:SXENAYVG + cheat + description:Infinite special moves + code:GXVPAZVG + cheat + description:9 special moves + code:PASAZALE + cheat + description:6 special moves + code:TASAZALA + cheat + description:Mega-jump + code:PAKAAGAE + cheat + description:Infinite time + code:GZOENISA + cheat + description:Faster timer + code:YPOAUSYU + cheat + description:Slower timer + code:YYOAUSYU + cheat + description:Start with less energy + code:TASATEGA + cheat + description:Start with more energy + code:APSATEGE + cheat + description:Infinite health + code:04CE:0C + cheat + description:Infinite lives (alt) + code:0082:10 + cheat + description:Infinite time (alt) + code:0032:03 + +cartridge sha256:e91bb35c7a95388c06f978c6cee73b1169fa7ec66b1808de5f504dcfefafbaab + title:Rolling Thunder (USA) (Unl) + cheat + description:Infinite health + code:SZSZGVSE + cheat + description:Infinite lives + code:SZNTULVG+SZSTULVG + cheat + description:Infinite time + code:SZEVYZVG + cheat + description:200 Machine Gun bullets on pick-up + code:EKSTEAGV + cheat + description:300 Machine Gun bullets and 300 bullets on pick-up + code:SUOZPXVS + cheat + description:Gain fewer bullets on pick-up + code:GOKVNAZL + cheat + description:Self-replenishing bullets + code:ZLVITYPA + cheat + description:Start with 200 bullets + code:EKXVZAZU + cheat + description:Start with 200 bullets on each new life + code:EGKVKLZU + cheat + description:Start with loads of ammunition + code:LEXTZAAA+LAKTKLAA + cheat + description:Start with 1 life + code:PEOVLALA + cheat + description:Start with 6 lives + code:TEOVLALA + cheat + description:Start with 9 lives + code:PEOVLALE + cheat + description:Start with 1 life after continue + code:PASPYZLA + cheat + description:Start with 6 lives after continue + code:TASPYZLA + cheat + description:Start with 9 lives after continue + code:PASPYZLE + cheat + description:Start with increased life meter + code:AEEVSAZE + cheat + description:Start on story 1 area 02 + code:PAVEUYAA+ALVESYOL + cheat + description:Start on story 1 area 03 + code:ZAVEUYAA+ALVESYOL + cheat + description:Start on story 1 area 04 + code:LAVEUYAA+ALVESYOL + cheat + description:Start on story 1 area 05 + code:GAVEUYAA+ALVESYOL + cheat + description:Start on story 2 area 06 + code:IAVEUYAA+ALVESYOL + cheat + description:Start on story 2 area 07 + code:TAVEUYAA+ALVESYOL + cheat + description:Start on story 2 area 08 + code:YAVEUYAA+ALVESYOL + cheat + description:Start on story 2 area 09 + code:AAVEUYAE+ALVESYOL + cheat + description:Start on story 2 area 10 + code:PAVEUYAE+ALVESYOL + cheat + description:Start on story 3 area 01 + code:PEKEXIAA + cheat + description:Infinite health (not versus bullets) + code:0089:02 + cheat + description:Infinite bullets + code:00A0:32 + cheat + description:Infinite time (alt) + code:059B:09+059C:09+059D:09 + cheat + description:Infinite lives (alt) + code:05BC:09 + +cartridge sha256:644291444ae16a02a128c613fa4e10559a45e4740e3614fb57b73b8c736bdbef + title:Roundball - 2-on-2 Challenge (USA) + cheat + description:Start with 1 ball - all players + code:PANGIPLA + cheat + description:Infinite balls - all players + code:SZKGPXVS + +cartridge sha256:fade44d9c76173afe098fbe02d859735e06b2c509fd80da08b1cc85bfc01a556 + title:Rush'n Attack (USA) + cheat + description:Invincibility (star effect) + code:KAXAGYIA+KAXEYYIA + cheat + description:Invincibility (except vs bullets) + code:AIUAPPEI + cheat + description:Infinite POW + code:AENASIPA + cheat + description:Always have 255 POW + code:SAVSNNSX + cheat + description:Infinite lives - P1 + code:GZOEAYVG + cheat + description:Infinite lives - P2 + code:GZOEIYVG + cheat + description:Multi-jump + code:NXSAGNUE+OAUXENNN+OYUXXNNY+PZUZXNNN+SZUZENNY+UAUXUNNN+AAUZUNNN+ATUXKNNY+AUSALYOY+AZUXONNY+AZUZVNNY+EYUZKNNY+EYUZNNNN+GAUZONNY+LAUZSNNY + cheat + description:Start with 1 life - P1 + code:PAVSTPIA + cheat + description:Start with 1 life - P2 + code:PANITPIA + cheat + description:Start with 10 lives - P1 + code:ZAVSTPIE + cheat + description:Start with 10 lives - P2 + code:ZANITPIE + cheat + description:Start on stage 2 (disable when stage begins) + code:0020:01 + cheat + description:Start on stage 3 (disable when stage begins) + code:0020:02 + cheat + description:Start on stage 4 (disable when stage begins) + code:0020:03 + cheat + description:Start on stage 5 (disable when stage begins) + code:0020:04 + cheat + description:Start on stage 6 (disable when stage begins) + code:0020:05 + +cartridge sha256:9bef1813dbcfa003b3b1978a66a8da3ff59c93dd74f1332801515aa4b633c51e + title:Rygar (USA) (Rev A) + cheat + description:Invincibility + code:ATEZOTKA + cheat + description:Infinite health + code:SXUZXTSA + cheat + description:Infinite Mind points + code:AAZEZZ + cheat + description:Have first three items after pressing B once + code:IEKZPLIZ + cheat + description:Hit anywhere + code:ALOXKIEL+ALUZUIEL+ALXZXIEL+EYUXOIEL + cheat + description:One hit kills + code:POXXVYSA + cheat + description:Pits aren't fatal (side view) + code:AAOZLEAA + cheat + description:Walk on water (side view) + code:ASSOSGEI + cheat + description:Enemies always drop a health potion + code:EPSLYIEL+LANUYIYA+OZNUTSPX + cheat + description:Enemies always drop a Mind unit + code:EPSLYIEL+GANUYIYA+OZNUTSPX + cheat + description:Don't be pushed after being hit + code:AVOXVTIA + cheat + description:Jump higher + code:LAVOLTGA + cheat + description:Multi-jump + code:ZZKXKIAX+APKXSIEY+ATOZTEOZ+AZKXXIGE+GASZOIIA+IZKXUSPZ+SAKXNSSX+SZKXOIXP+XGSZEIZL+XTKXESSX + cheat + description:Grappling Hook continues until it finds something + code:SZUPOOVK+SZXXGZSA + cheat + description:Start with 12 units of health + code:AOUGPATE+AOUGZATE + cheat + description:Infinite Attack & Assail + code:00CD:FF + cheat + description:Have all equipment + code:00C0:FF+00C1:FF + cheat + description:Always have Power Up + code:00C0:10 + cheat + description:Lots of Tone + code:00C7:FF + cheat + description:Lots of Last + code:00C8:FF + +cartridge sha256:e3a7e0b559b18e8e2fd6f2bf0fdadbf9094be63a01bac50e5505413e1d7697a4 + title:Rygar (USA) + cheat + description:Invincibility + code:ATEZOTKA + cheat + description:Infinite health + code:SXUZXTSA + cheat + description:Infinite Mind points + code:AAZEZZ + cheat + description:Have first three items after pressing B once + code:IEKZPLIZ + cheat + description:Hit anywhere + code:ALOXKIEL+ALUZUIEL+ALXZXIEL+EYUXOIEL + cheat + description:One hit kills + code:POXXVYSA + cheat + description:Pits aren't fatal (side view) + code:AAOZLEAA + cheat + description:Walk on water (side view) + code:ASSOSGEI + cheat + description:Enemies always drop a health potion + code:EPSLYIEL+LANUYIYA+OZNUTSPX + cheat + description:Enemies always drop a Mind unit + code:EPSLYIEL+GANUYIYA+OZNUTSPX + cheat + description:Don't be pushed after being hit + code:AVOXVTIA + cheat + description:Jump higher + code:LAVOLTGA + cheat + description:Multi-jump + code:ZZKXKIAX+APKXSIEY+ATOZTEOZ+AZKXXIGE+GASZOIIA+IZKXUSPZ+SAKXNSSX+SZKXOIXP+XGSZEIZL+XTKXESSX + cheat + description:Grappling Hook continues until it finds something + code:SZUPOOVK+SZXXGZSA + cheat + description:Start with 12 units of health + code:AOUGPATE+AOUGZATE + cheat + description:Infinite Attack & Assail + code:00CD:FF + cheat + description:Have all equipment + code:00C0:FF+00C1:FF + cheat + description:Always have Power Up + code:00C0:10 + cheat + description:Lots of Tone + code:00C7:FF + cheat + description:Lots of Last + code:00C8:FF + +cartridge sha256:9579a2b5a4083420d9bc3788cae39b068c0752ac68e7b7dc1be1d748cb2b7133 + title:S.C.A.T. - Special Cybernetic Attack Team (USA) + cheat + description:Infinite health + code:AANSUGPA + cheat + description:More energy on pick-up + code:ZANVNGLE + cheat + description:Don't lose speed-ups when hit + code:AEESVKAA + cheat + description:Longer immunity + code:NNEIKGAK + cheat + description:Shorter immunity + code:APKSEGAG + cheat + description:Faster maximum speed-up + code:PAEIKTTE+NYEISVXY + cheat + description:Faster normal speed-up + code:TENIKIGA+XNNISSKN + cheat + description:Start with more health + code:ZUXGKTTA + cheat + description:Infinite health - P1 + code:001C:09 + +cartridge sha256:4d6e58f232dc1a592583889f858eac230b8e8921e715276e580073ab2dd18546 + title:Saint Seiya - Ougon Densetsu (Japan) + cheat + description:Fly + code:008B:C8 + cheat + description:Infinite health (damage) + code:0689:40+068A:40 + cheat + description:Infinite Cosmos + code:0685:40+0686:40 + +cartridge sha256:3ad57c83631233530bb421b14236fdba70d18f70ce46a8410ec7c2f156b559ab + title:Saint Seiya - Ougon Densetsu Kanketsu Hen (Japan) + cheat + description:Start with infinite health (life) + code:0063:40+0040:40 + cheat + description:Start with infinite Cosmos + code:0059:40+005A:40 + cheat + description:Infinite Seven Sense + code:05AA:40+05AB:40 + +cartridge sha256:9e8eb95ec2917597650131db254067ff59bc3669417563165518927357812c73 + title:Salamander (Japan) + cheat + description:Invincibility + code:0074:20 + cheat + description:Infinite lives + code:0034:09 + cheat + description:Option always on Speed + code:0068:01 + cheat + description:Option always on Missile + code:0068:02 + cheat + description:Option always on Ripple + code:0068:03 + cheat + description:Option always on Laser + code:0068:04 + cheat + description:Option always on Option + code:0068:05 + cheat + description:Option always on Force + code:0068:06 + cheat + description:Start with and keep Missiles + code:0076:02 + +cartridge sha256:7ee2b81ef8ab8e9c009ecd42ed5fa5a34e3e48896c3567fac1ca7520c1de870e + title:Secret Scout in the Temple of Demise (USA) (Unl) + cheat + description:Infinite lives + code:OUXTYKOO + cheat + description:View the ending + code:ASVIYIAE + +cartridge sha256:c33611fb6b3ced6cf0ab4cd8e6795be44dc164efd453a69bad404c95837ec420 + title:Secret Ties (USA) (Proto) + cheat + description:Invincibility + code:SKNKUEKK + cheat + description:Infinite health + code:SZVGEPSA + cheat + description:Infinite lives + code:SKVNKZVG + cheat + description:Infinite Gun + code:SZVGLYVG + cheat + description:Infinite Shield + code:SZOKSPVG + cheat + description:Super-jump + code:YONGAIIE+AXVGYGTA + cheat + description:Allways able to use Gun + code:AIXTXYEI + cheat + description:Allways able to use Shield + code:AIOVKYEI + cheat + description:Start with 99 lives + code:GVVTAPLA + cheat + description:Start with double health + code:ZENVPPIE + cheat + description:Invincibility (alt) + code:03CC:00 + cheat + description:Infinite health (alt) + code:0009:07 + cheat + description:Infinite Gun (alt) + code:000A:63 + cheat + description:Infinite Shield (alt) + code:000B:63 + +cartridge sha256:a98e48a26c104375ae45e5c1bc4eb7b2a446e0e9ffa7ed3923c3cf5eec9a549a + title:Section-Z (USA) + cheat + description:Infinite lives + code:SXOPUIVG + cheat + description:Energy tube gives full energy boost + code:ZAUNUZAE + cheat + description:Autofiring capability + code:NNNOUTSY + cheat + description:Autofire without having to hold the button down + code:NNNOUTSN + cheat + description:Press Start to complete current mission (do not use past sector 40) + code:AEOIILYA+OXOIPUPK+PUOIGUSN+ZEOIZLPA + cheat + description:Start a new game to view the ending + code:LAEAZYPA + cheat + description:Start with 1 life + code:PEXSIZLA + cheat + description:Start with 6 lives + code:TEXSIZLA + cheat + description:Start with 9 lives + code:PEXSIZLE + cheat + description:Infinite energy + code:005B:09+005A:09 + +cartridge sha256:afc7ce7262cc03039481b9338a94db35a1f4e9e54ee3dd34f979a7921d4a5e29 + title:Seicross (USA) + cheat + description:Infinite lives + code:SUTEEX + cheat + description:Slow motion + code:PEGEUG + cheat + description:Start with 1 life + code:PELAGA + cheat + description:Start with 6 lives + code:TELAGA + cheat + description:Start with 9 lives + code:PELAGE + cheat + description:Infinite health - P1 + code:0078:BD + cheat + description:Infinite lives - P1 + code:0615:99 + +cartridge sha256:2395a8a102bfc403bb2c474f77035483792ec15bce37695c9f2d96d62bc8fe10 + title:Shadow of the Ninja (USA) + cheat + description:Infinite continues + code:SZSNIIVG + cheat + description:9 continues + code:PEEVZAIE + cheat + description:1 continue + code:PEEVZAIA + cheat + description:Don't lose energy from enemy attacks + code:GZVXSKSO + cheat + description:Don't lose energy from falling + code:AAVPGIGA + cheat + description:Maximum energy gained from potion + code:APOEOGGA + cheat + description:Less energy gained from potion + code:PAOEOGGA + cheat + description:40 Throwing Stars on pick-up + code:AZUAOGGO + cheat + description:20 Bombs on pick-up + code:GPKAVGIA + +cartridge sha256:fbc69cdaf7c1419906d8cf2a74ab70d11520b2f3877387b8fd70460b6e6dd542 + title:Shadowgate (USA) + cheat + description:Infinite torches + code:XVESZNVK + +cartridge sha256:c3f361c4a1441101d6a3eb42f5776073c712198e7ed45d6ab5350816ea15aee4 + title:Shatterhand (USA) + cheat + description:Power-ups don't use up gold + code:AAKKSPPA + cheat + description:Big coins worth double + code:AXXAZZGO + cheat + description:Big coins worth half + code:ZEXAZZGO + cheat + description:Small coins worth triple + code:YEEAYZIE + cheat + description:Start with less health + code:GENNZSAA + cheat + description:Start with 1 life + code:AEVNAIZA + cheat + description:Start with 6 lives + code:IEVNAIZA + cheat + description:Start with 9 lives + code:AEVNAIZE + cheat + description:Invincibility - Robot Suit + code:05C2:7E + cheat + description:Powered up - Red Vest + code:05C8:03 + +cartridge sha256:2b85e6411f42597ceab01f5eb3ba9fd362b07340c0665fd533a3c3d5f2b1e972 + title:Shinobi (USA) (Unl) + cheat + description:Infinite life + code:SZNIPNVK + cheat + description:Infinite lives + code:SZEOLXVK + cheat + description:Turbo running + code:IEKONILA + cheat + description:Start with double life + code:GAXOTATE+GENPGPTE + cheat + description:Start with 1 life + code:AANOLAZA + cheat + description:Start with 6 lives + code:IANOLAZA + cheat + description:Start with 9 lives + code:AANOLAZE + +cartridge sha256:6c705f7980a08b7a7a5d74ddfd175155492168248f65c7d9e3cef1a6b14a2886 + title:Shooting Range (USA) + cheat + description:Double bonus time for hourglasses + code:GTEPOAZL + cheat + description:Half bonus time for hourglasses + code:PPEPOAZU + cheat + description:More time for level 1 + code:GEKAILLA+GAEETTLA + cheat + description:Less time for level 1 + code:ZEKAILLA+ZAEETTLA + cheat + description:More time for level 2 + code:GAOAATZA+AAOAPTZL + cheat + description:Less time for level 2 + code:PAOAATZA+ZLOAPTZL + cheat + description:More time for level 3 + code:GAOAZTZA+ZLOALTAA + cheat + description:Less time for level 3 + code:PAOAZTZA+AAOALTAA + cheat + description:Double usual shots per round + code:ASUAIVAZ+ASXOVXAZ+SXVONOOU + cheat + description:Triple usual shots per round + code:ASUAIVAZ+ANXOVXAX+SXVONOOU + cheat + description:Quadruple usual shots per round + code:ASUAIVAZ+EXXOVXAZ+SXVONOOU + +cartridge sha256:37a5cfb1aacd9bb42746f20923441b5f613971d4dc99de68c216b10a8d7bcbfc + title:Silent Service (USA) + cheat + description:Infinite deck gun shells + code:SZXVOPVG + cheat + description:Infinite bow torpedoes + code:SZSVUPVG + cheat + description:Infinite aft torpedoes + code:SXETUPVG + cheat + description:Start with 50 deck gun shells + code:ZLEPOIAI + cheat + description:Start with 99 deck gun shells + code:LTEPOIAI + +cartridge sha256:28f0444e178830edf654eb72e54c7920296156524295b5a4f4418fc4d33f42fd + title:Silk Worm (USA) + cheat + description:Infinite lives using helicopter + code:SXSVIZVG + cheat + description:Infinite lives using jeep + code:SZVVGTVG + cheat + description:Keep firepower and speed-ups for helicopter + code:SZETZLSA + cheat + description:Keep firepower and speed-ups for jeep + code:SXOTPTSA + cheat + description:Restrict movement area for helicopter + code:EEOVYUEI + cheat + description:Restrict movement area for jeep + code:EEOVGYEV + cheat + description:1 life using helicopter after continue + code:PEEGSPLA + cheat + description:6 lives using helicopter after continue + code:TEEGSPLA + cheat + description:9 lives using helicopter after continue + code:PEEGSPLE + cheat + description:1 life using jeep after continue + code:PEOKNPLA + cheat + description:6 lives using jeep after continue + code:TEOKNPLA + cheat + description:9 lives using jeep after continue + code:PEOKNPLE + cheat + description:Start with 1 life + code:PAXGXALA + cheat + description:Start with 6 lives + code:TAXGXALA + cheat + description:Start with 9 lives + code:PAXGXALE + cheat + description:Start at stage 2 + code:PAXKEAAA + cheat + description:Start at stage 3 + code:ZAXKEAAA + cheat + description:Start at stage 4 + code:LAXKEAAA + cheat + description:Start at stage 5 + code:GAXKEAAA + cheat + description:Start at stage 6 + code:IAXKEAAA + cheat + description:Start at stage 7 + code:TAXKEAAA + +cartridge sha256:718dce0398dba4f8968969fe3e078f55ea0a5b3cff91895fd9ac0225fe4c437e + title:Silver Surfer (USA) + cheat + description:Infinite lives - both players + code:SXEKSNVK + cheat + description:Infinite Smart Bombs - both players + code:NYVTLVGO + cheat + description:Keep cosmic weapons after losing a life + code:GXEITSSE + cheat + description:Keep Orbs after losing a life + code:GXEILSSE+GXKIOUSE + cheat + description:Have 5 Smart Bombs on a new life + code:IEESIIPA + cheat + description:Start with 1 life - P1 + code:PAOILIIA + cheat + description:Start with 1 life - P2 + code:PAKSGIIA + cheat + description:Start with 5 Smart Bombs - P1 + code:IAXSGIPA + cheat + description:Start with 5 Smart Bombs - P2 + code:IAVIIIPA + cheat + description:Infinite lives + code:05E6:09 + +cartridge sha256:ce1fd1fcf89d2d6334cc3d96101c7b995ff4959257ed04df92f0afad711d08da + title:Simpsons, The - Bartman Meets Radioactive Man (USA) + cheat + description:Invincibility + code:SXXNPLAX + cheat + description:Infinite health + code:AAUY-PYGA + cheat + description:Infinite health (alt) + code:SZUYZNSE + cheat + description:Infinite Eyes on pick-up + code:SKNNVEVK + cheat + description:Infinite Eyes on pick-up (alt) + code:SXNNVEVK + cheat + description:Infinite Cold on pick-up + code:AAKYKPPA + cheat + description:Infinite lives + code:OLVYAZOP + cheat + description:Infinite credits + code:SZENNEVK + cheat + description:Eyes worth more on pick-up + code:ASVTOZAZ + cheat + description:Cold worth more on pick-up + code:AXUVSZIA + cheat + description:Start with 2 lives and 2 credits + code:PAVAYYLA + cheat + description:Start with 6 lives and 6 credits + code:IAVAYYLA + cheat + description:Start with 8 lives and 8 credits + code:YAVAYYLA + cheat + description:Start with 10 lives and 10 credits + code:PAVAYYLE + cheat + description:Start in chapter 1 level 2 + code:ZAUZAYAA + cheat + description:Start in chapter 1 level 3 + code:IAUZAYAA + cheat + description:Infinite health (alt 2) + code:0787:20 + cheat + description:Infinite Eyes on pick-up (alt 2) + code:0788:99 + cheat + description:Infinite Cold on pick-up (alt) + code:789:99 + +cartridge sha256:7e8a3accbd57c9fea4f86fb9f99d9adc579bacec52fc68d547125067f8e50816 + title:Simpsons, The - Bart vs. the Space Mutants (USA) (Rev A) + cheat + description:Infinite time + code:XVOYLXXK + cheat + description:Slow down time + code:AYNNIXGU + cheat + description:Speed up time + code:AZNNIXGL + cheat + description:Gain 2 coins for every 1 collected + code:PAENGYAA + cheat + description:Only 10 coins needed to get an extra life + code:PAOYZNTE + cheat + description:Buy items for free + code:GXOXIXVK+GXXLIEVK + cheat + description:Super-jump + code:IPUYVUGA + cheat + description:Invincibility (blinking) + code:04BD:FF + cheat + description:Infinite health + code:04B2:01 + cheat + description:Infinite time (alt) + code:066C:09 + +cartridge sha256:346fd8061a0b09c057855536012b146256bfbe386e304ef950ad93603048933c + title:Simpsons, The - Bart vs. the Space Mutants (USA) + cheat + description:Invincibility + code:ESOINPEY + cheat + description:Infinite health + code:SZOTESVK + cheat + description:Infinite time + code:XVONYXXK + cheat + description:Slow down time + code:ANENPXGU + cheat + description:Speed up time + code:AXENPXGL + cheat + description:Gain 2 coins for every 1 collected + code:PAONAYAA + cheat + description:Only 10 coins needed to get an extra life + code:PAONTNTE + cheat + description:Buy items for free + code:GXXZZOVK+GXXULEVK + cheat + description:Get all items by selecting them (be sure to get the Paint Can in level 1 and Gun in the Museum) + code:SPKTLESU + cheat + description:Super-jump + code:IPKYXUGA + cheat + description:Invincibility (blinking) + code:04BD:FF + cheat + description:Infinite health (alt) + code:04B2:01 + cheat + description:Infinite time (alt) + code:066C:09 + +cartridge sha256:678565338a9efa2d9d4bd399b314b62864d486a4e9f4c314bf11ae5a240cdab8 + title:Simpsons, The - Bart vs. the World (USA) + cheat + description:Invincibility + code:ZOXVGLIE + cheat + description:Infinite health + code:SZVVEKVK + cheat + description:Infinite lives + code:SZONIPST + cheat + description:Infinite Firecracker Balls + code:OLUNPPOP + cheat + description:Infinite tries for the card match game + code:SZNZPEVK + cheat + description:Bart flies + code:KLYUKA + cheat + description:Lose lives more easily + code:EISVNGEY + cheat + description:Start with 99 Firecracker Balls + code:PAEZPAAE + cheat + description:Start with 9 lives + code:PAXXVGLE + cheat + description:Infinite health (alt) + code:06BC:05 + cheat + description:Infinite lives (alt) + code:06C1:09 + cheat + description:Infinite Firecracker Balls (alt) + code:06BF:09 + +cartridge sha256:fe4043430276177b739137ee7ed8e6cb75e751732a3f796ce03708d3ef1755e8 + title:Skate or Die (USA) + cheat + description:Snowball Blast - More snowballs picked up + code:ZENXTTPA + cheat + description:Snowball Blast - Start with more time + code:OOEPVAAV + cheat + description:Snowball Blast - Start with less time + code:AKEPVAAT + cheat + description:Snowball Blast - More time gained + code:IOKXITAP + cheat + description:Snowball Blast - Less time gained + code:IEKXITAP + cheat + description:Snowball Blast - Start with more ammo + code:GAUPVAZA + cheat + description:Snowball Blast - Start with less ammo + code:PAUPVAZA + cheat + description:Acro Aerials - More jumps allowed + code:IAVVNILA+IESTEYLA + +cartridge sha256:3626bb5ce3035b39d70ed5f2941b69801c1a95629609f1ebd90a5a6a9e16794f + title:Skate or Die 2 - The Search for Double Trouble (USA) + cheat + description:Adventure Game - Infinite health + code:SXUXZPVG + cheat + description:Adventure Game - Infinite Paint Clips + code:SXVPTVVK + cheat + description:Adventure Game - Infinite Eggs + code:AANPZPPA+AAXOZLPA + cheat + description:Adventure Game - Infinite M-80's + code:AAVPTLPA+AEEOAPPA + cheat + description:Adventure Game - Skate at any speed + code:AEESAAPG+AAKATAPG + cheat + description:Stunt Ramp - Only 1 skateboard + code:PAUYLLLA + cheat + description:Stunt Ramp - 6 skateboards + code:TAUYLLLA + cheat + description:Stunt Ramp - 9 skateboards + code:PAUYLLLE + cheat + description:Stunt Ramp - More time + code:TAONILLA + cheat + description:Stunt Ramp - Less time + code:ZAONILLA + cheat + description:Stunt Ramp - Infinite time + code:SZUAKZVG + cheat + description:Stunt Ramp - Super speed + code:TEKOKZIA + cheat + description:Stunt Ramp - Infinite skateboards + code:SXKPVYVG+SXUZGAVG + +cartridge sha256:a29461c583ec03909c1dbc4e7d783de0aaf2f391ae8329b3d8bf06e06cfdd2fa + title:Ski or Die (USA) + cheat + description:Snowball Blast - More snowballs picked up + code:ZENXTTPA + cheat + description:Snowball Blast - Start with more time + code:OOEPVAAV + cheat + description:Snowball Blast - Start with less time + code:AKEPVAAT + cheat + description:Snowball Blast - More time gained + code:IOKXITAP + cheat + description:Snowball Blast - Less time gained + code:IEKXITAP + cheat + description:Snowball Blast - Start with more ammo + code:GAUPVAZA + cheat + description:Snowball Blast - Start with less ammo + code:PAUPVAZA + cheat + description:Acro Aerials - More jumps allowed + code:IESTEYLA+IAVVNILA + +cartridge sha256:06fddd300a6d1cbe1be92e851e3d5d2defcc7e682903b569bc9fe71a26addd74 + title:Skull & Crossbones (USA) (Unl) + cheat + description:Infinite continues + code:SZNOTNVK + cheat + description:Infinite weapons + code:SUOEIVVS + cheat + description:Infinite time + code:SZONGXVK + cheat + description:Faster timer + code:AZONAXGL + cheat + description:Slower timer + code:AYONAXGL + cheat + description:Half energy for Red Dog and One Eye + code:POVPLYZU+POEPZYZU + cheat + description:Double energy for Red Dog and One Eye + code:LVVPLYZL+POEPZYZU + cheat + description:Better super-jump + code:EUVEYNEK+EUVAGNEK + cheat + description:1 continue + code:PEXPTYIA + cheat + description:9 continues + code:PEXPTYIE + +cartridge sha256:51958d12a19e7c573fab26b85fe81d57330ff6668d630c6bc95c7c563c441e93 + title:Sky Kid (USA) + cheat + description:Infinite lives + code:SXEKGZVI + cheat + description:P1 has more lives than P2 + code:VANNVZSA + cheat + description:Shoot more bullets + code:AAOKIZPA + cheat + description:Start with 1 life - both players + code:PANYNZLA + cheat + description:Start with 6 lives - both players + code:TANYNZLA + cheat + description:Start with 9 lives - both players + code:PANYNZLE + cheat + description:Start on level 5 + code:IAVNNZPA+GAVNUZAA + cheat + description:Start on level 10 + code:ZAVNNZPE+PAVNUZAE + cheat + description:Start on level 15 + code:APVNNZPA+YAVNUZAE + cheat + description:Start on level 20 + code:GPVNNZPA+LPVNUZAA + cheat + description:Invincibility - P1 + code:00BB:00 + cheat + description:Invincibility - P2 + code:00CB:00 + +cartridge sha256:f845ee19cbe21f5b463073f3716659f9c82ef6342a20879165ed21f219f6653b + title:Sky Shark (USA) (Rev 0A) + cheat + description:Infinite lives + code:OZNEAAVS + cheat + description:Infinite Bombs + code:GXUEALVI + cheat + description:Infinite credits + code:GZNEIOVS + cheat + description:Autofire + code:AAEELOGI + cheat + description:Double Bombs + code:TAVPSTLA + cheat + description:Double credits + code:TAUAYALA + cheat + description:1 life after continue - both players + code:AANEZPGA + cheat + description:9 lives after continue - both players + code:AANEZPGE + cheat + description:Start with maximum firepower + code:EZXAPPKZ+TAXAZOIL + cheat + description:Start with 1 life - P1 + code:GZXATEOZ + cheat + description:Start with 1 life - P2 + code:AAUALAGA + cheat + description:Start with 9 lives - P1 + code:TAXEZAXZ+PZXELENY + cheat + description:Start with 9 lives - P2 + code:AAUALAGE + +cartridge sha256:f7f6d714c7758f679db8f0c7869ef19353fdcc49c267494bb41bfefda0f152d6 + title:Slalom (USA) + cheat + description:Ski super fast + code:PAOULZAA + cheat + description:No track obstacles + code:AAEPLIPA + cheat + description:Timer at 5 minutes for all tracks + code:XZXPATVZ+PAXPPVPN + +cartridge sha256:6dde1137253e7e41972dd04e09dc736efee82cc7f41f8deac8d0dcb111301616 + title:Smash T.V. (USA) + cheat + description:Infinite lives + code:UIVYGXVS + cheat + description:Touch and kill most enemies + code:EAOZPZEY + cheat + description:Infinite Grenades + code:OXXUUYVS + cheat + description:Get a lot more Grenades + code:OPNXVTTE + +cartridge sha256:8df9c1a7a3806873db908604bb99749673241ccd58e1b32a6d7bf2fafc97d9d4 + title:Smurfs, The (Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:EIEAELEY+ESNXPLEY + cheat + description:Infinite health + code:SXKPLVVK + cheat + description:Infinite lives + code:SXOLXUSE + cheat + description:Infinite time + code:SUKPSOSO + +cartridge sha256:c85ed147e6da0da5ef02c930cc52621ae38d66971a332d168bf31126a3a740ce + title:Snake's Revenge (USA) + cheat + description:Invincibility + code:SZEVEPSA + cheat + description:Infinite health + code:SXKVKASA + cheat + description:Infinite ammo for all weapons + code:XTNTZVEE + cheat + description:Infinite Beretta ammo + code:SZEEOUSE + cheat + description:Infinite Shotgun ammo + code:SXOASKSE + cheat + description:Infinite Grenades + code:SZKAKKSE + cheat + description:Infinite Missiles + code:SXVEOKSE + cheat + description:Reduce your injuries by up to 50% + code:AEUVOAYA + cheat + description:Play with less health + code:XVUYTUZE+XTKZXKZE + cheat + description:Infinite time for Metal Gear battle + code:SXSZTEVK + cheat + description:One hit defeats Metal Gear + code:ESXALLEY + cheat + description:Start a new game to view the ending + code:PPUGASTA + cheat + description:Start with half bullets for Beretta M92 + code:AXXVGYAG + cheat + description:Start with double bullets for Beretta M92 + code:EEXVGYAG + cheat + description:Start with Machine Gun instead of Beretta + code:ZEOVAYPA+XKXVTYEG + cheat + description:Start with Shotgun instead of Beretta + code:GEOVAYPA+KKXVTYEG + cheat + description:Start with Grenades instead of Beretta + code:AXOVAYPA+VKXVTYEG + cheat + description:Start with Missiles instead of Beretta + code:EEOVAYPA+EKXVTYEK + +cartridge sha256:98691aea357072f901095e47db056a01887083fd81710d425b9171db1cd1ad1b + title:Snake Rattle n Roll (USA) + cheat + description:Infinite lives - both players + code:SLOUSVVS + cheat + description:Infinite time + code:SXEYOZVG + cheat + description:Faster timer + code:AGNNVXTT + cheat + description:Slower timer + code:EPNNVXTT + cheat + description:Super-jump + code:ZAXOSGPA + cheat + description:Mega-jump + code:LAXOSGPA + cheat + description:1 life - both players + code:AEXAYZZA + cheat + description:6 lives - both players + code:IEXAYZZA + cheat + description:9 lives - both players + code:AEXAYZZE + cheat + description:1 life - both players, after continue + code:AEUAETZA + cheat + description:6 lives - both players, after continue + code:IEUAETZA + cheat + description:9 lives - both players, after continue + code:AEUAETZE + cheat + description:Start on level 2 + code:PEUEGXNY + cheat + description:Start on level 3 + code:ZEUEGXNY + cheat + description:Start on level 4 + code:LEUEGXNY + cheat + description:Start on level 5 + code:GEUEGXNY + cheat + description:Start on level 6 + code:IEUEGXNY + cheat + description:Start on level 7 + code:TEUEGXNY + cheat + description:Invincibility (blinking) + code:040D:11 + cheat + description:Infinite health + code:059F:1C + cheat + description:Infinite lives + code:03DF:03 + cheat + description:Infinite time (alt) + code:00CF:09 + cheat + description:Easy win + code:0062:09 + cheat + description:Max tongue height + code:0499:07 + +cartridge sha256:fbd7caadaf77c2b191e74328b9b836155f8498500f7e5af44edfc0ec53b15fee + title:Snow Brothers (USA) + cheat + description:Invincibility + code:SUUAVVVS + cheat + description:Infinite number of chances + code:SXNEUYVI + cheat + description:Always get 10 chances after a continue (count restarts at 9) + code:PAOAYLZE + cheat + description:Always get 1 chance after a continue (count restarts at 0) + code:AAOAYLZA + cheat + description:Don't lose super ability after you lose a chance + code:OUOOGEOO + cheat + description:Start with 10 chances instead of 3 (count starts at 9 instead of 2) + code:PAXXPLZE + cheat + description:Start with 1 chance (count starts at 0) + code:AAXXPLZA + cheat + description:Start with Speed Skates, Power Shots and super snow-throwing + code:YAEEYAAE + cheat + description:Start with Speed Skates (don't use with other "start with" codes) + code:PAEEYAAA + cheat + description:Start with Power Shots (don't use with other "start with" codes) + code:ZAEEYAAA + cheat + description:Start with super snow-throwing ability (don't use with other "start with" codes) + code:GAEEYAAA + cheat + description:Start on 5th floor + code:GEVZTZAA + cheat + description:Start on 10th floor + code:PEVZTZAE + cheat + description:Start on 20th floor + code:LOVZTZAA + cheat + description:Start on 30th floor + code:IOVZTZAE + cheat + description:Start on 40th floor + code:YXVZTZAA + cheat + description:Start on 50th floor + code:PUVZTZAA + +cartridge sha256:6a0c8be0f6445d9d777080955c7aa8fbff7497633b878a36c8139ec13dabfb8b + title:Soccer (World) + cheat + description:Each half lasts only 10 minutes + code:APOOKZIP + cheat + description:Each half lasts for 50 minutes + code:AIOOKZIP + cheat + description:Start 1 goal up + code:PASLVTAA+KASUOTSA+KASUUVSE + cheat + description:Start 3 goals up + code:LASLVTAA+KASUOTSA+KASUUVSE + +cartridge sha256:45a0fd35f3141c140fb8d1f652876011f28d772b987da123c597aa8c924437b2 + title:Solar Jetman - Hunt for the Golden Warpship (USA) + cheat + description:No damage taken from walls + code:AEXZGVSY+AEXXAVNY + cheat + description:Minimum damage taken from walls + code:AEXXAVNY + cheat + description:Infinite lives + code:SZXONIVG + cheat + description:Weapons use up no energy + code:SVEKOVON + cheat + description:Items for free + code:AEUIOXYA+GXKSOZSA + cheat + description:Reversed gravity for planet 1 + code:UNSPLSLE + cheat + description:Reversed gravity for planet 2 + code:VTSOZVTO + cheat + description:Reversed gravity for planet 3 + code:KVOPATGP + cheat + description:Reversed gravity for planet 4 + code:XNVOTSZE + cheat + description:Reversed gravity for planet 5 + code:ETXPGTAZ + cheat + description:Reversed gravity for planet 6 + code:OTUOYVPX + cheat + description:Reversed gravity for planet 7 + code:UTEOPTLZ + cheat + description:Normal gravity for planet 8 + code:AOXOLVEV + cheat + description:Start with 1 ship and 1 life + code:PAKSZLGA + cheat + description:Start with 8 ships and 8 lives + code:AAKSZLGE + cheat + description:Start with more money + code:AASSZLPE + cheat + description:Start on level 3 + code:ZASSTLAA + cheat + description:Start on level 6 + code:IASSTLAA + cheat + description:Start on level 9 + code:AASSTLAE + cheat + description:Start on level 11 + code:ZASSTLAE + +cartridge sha256:842478f0d9f01c6c547672a7e4dc4a33ed2c900f92e4b318f4d5941ba548b355 + title:Solomon's Key (USA) + cheat + description:Invincibility + code:SZVAIAAX + cheat + description:Infinite life + code:OUXZYPOP + cheat + description:Infinite lives + code:XTKKKEXK + cheat + description:Indestructible fireball + code:GZOXLAAX + cheat + description:Continuous fairies + code:AAXZIALZ + cheat + description:Start with 40,000 life points + code:KAXOOEVE + cheat + description:Start on last level reached + code:GZUPTOSE + cheat + description:Start on next level + code:VTUPTOSE + cheat + description:Start on level 10 + code:SZUOPOSE+UPUOLPGA+PAUPIPAE + cheat + description:Start on level 20 + code:SZUOPOSE+UPUOLPGA+LPUPIPAA + cheat + description:Start on level 30 + code:SZUOPOSE+UPUOLPGA+IPUPIPAE + cheat + description:Start on level 40 + code:SZUOPOSE+UPUOLPGA+YZUPIPAA + cheat + description:Invincibility (alt) + code:0028:80 + cheat + description:Infinite life (alt) + code:0438:09 + cheat + description:Infinite fireballs + code:042F:80 + +cartridge sha256:e437dbafa7e20dd72412c869b9433901c3e9302cfa16b6e8379ecc56ae8dcc22 + title:Solstice - The Quest for the Staff of Demnos (USA) + cheat + description:Infinite lives + code:SZSESXVK + cheat + description:Infinite Potions + code:SUSPIXVS + cheat + description:Multi-jump + code:SXUXYGAX + cheat + description:1 life after continue + code:PAXELPLA + cheat + description:8 lives after continue + code:AAXELPLE + cheat + description:Start with full flasks of Potions + code:GAOEUIZA + cheat + description:Start with no Potions + code:AAOEUIZA + cheat + description:Start with 1 life + code:PAKAVIGA + cheat + description:Start with 8 lives + code:AAKAVIGE + cheat + description:Infinite lives (alt) + code:0789:09 + cheat + description:Infinite Green Potion + code:0784:04 + cheat + description:Infinite Yellow Potion + code:0785:04 + cheat + description:Infinite Light Purple Potion + code:0786:04 + cheat + description:Infinite Dark Purple Potion + code:0787:04 + +cartridge sha256:cce92c9404d5dd48680b0b505acbbbce279a4f09606167f0aacfb6da991aac4c + title:Space Hunter (Japan) + cheat + description:Infinite energy + code:SZOLGNVK+SXOLYVSO + +cartridge sha256:dbd587ef5a12e03a336cda61cd120b4e8c585f45d82821e144ee8afdea9ee84e + title:Spartan X 2 (Japan) + cheat + description:Infinite health + code:SXEIXKVK+SZUSVKSE + +cartridge sha256:6f58c6fb427cf18b4c28f07909db642abac09fac2d7ae7dc9c99f1cd79263d95 + title:Spelunker (USA) + cheat + description:Invincibility + code:ATKPAIAZ+TUEEYKNN+GXOAPKIX + cheat + description:Infinite lives + code:IXOOPSVK + cheat + description:Invisibility + code:AEXAYTAP + cheat + description:Jump higher + code:SNEAKEVN+EANEEAAA + cheat + description:Start with 1 life + code:AANATPZA + cheat + description:Start with 6 lives + code:IANATPZA + cheat + description:Start with 9 lives + code:AANATPZE + cheat + description:Infinite lives (alt) + code:0234:63 + cheat + description:Have a high score + code:022F:FF + cheat + description:Infinite Bombs + code:0237:09 + cheat + description:Infinite Flares + code:0238:09 + +cartridge sha256:1104d574711a103745aed2407997275e1ac43fd4d5c7ff96bde0af5bfa014c2d + title:Spider-Man - Return of the Sinister Six (USA) + cheat + description:Invincibility + code:SXNUIZAX + cheat + description:Infinite health + code:SXOKVVSE + +cartridge sha256:3c74b191d7d4cb6c34e6b2d5f76d9c86be63f8ebb61581c49810f0dd58c538c1 + title:Spiritual Warfare (USA) (v6.1) (Unl) + cheat + description:Infinite energy + code:SXVGLGSA + cheat + description:Infinite Vial Of God's Wrath + code:SXKGXIVG + cheat + description:Start with all armors, 7 of each fruit, all items, 99 Keys, 255 God's Wrath, 99 Birds + code:NYEUYIAE + cheat + description:Start with max energy + code:APKLZITE + +cartridge sha256:5a82a1b0386407f1036c3d0ae750741c0835336f062d77480e1dd5b4da507386 + title:Spiritual Warfare (USA) (v6.0) (Unl) + cheat + description:Infinite energy + code:SXUKLGSA + cheat + description:Infinite Vial Of God's Wrath + code:NNSUYGAE + cheat + description:Start with all armors, 7 of each fruit, all items, 99 Keys, 255 God's Wrath, 99 Birds + code:NNSUYGAE + cheat + description:Start with max energy + code:APOLZITE + +cartridge sha256:14a86d409cc9e6ae2428f301e4aaa77290fe38ec3e660d971af9abda772747e2 + title:Spiritual Warfare (USA) (v5.1) (Unl) + cheat + description:Infinite energy + code:SXNKPGSA + cheat + description:Infinite Vial Of God's Wrath + code:SXSKEIVG + cheat + description:Start with all armors, 7 of each fruit, all items, 99 Keys, 255 God's Wrath, 99 Birds + code:NYXLIIAE + cheat + description:Start with max energy + code:APSUAITE + +cartridge sha256:387d82471ca5f54e70b3c4d445ae5c692640d99c47b30a6bf67f5a17b6236c85 + title:Splatter House - Wanpaku Graffiti (Japan) + cheat + description:Hit anywhere + code:AAKXGPLA+AAUXPOLP+GZUZGPEL + cheat + description:Moon-jump + code:AXXKLGAX+EEXGILIA+PXXGGUOK+YVXGLUNA + +cartridge sha256:17da401495807145c9d4db275d429b7fe94be45dde00edc40aca885911cfd138 + title:Spy Hunter (USA) + cheat + description:Infinite health + code:SXVPEZSA + cheat + description:Infinite lives + code:SXKAYOVK + cheat + description:Infinite lives (alt) + code:SZEUSGVG + cheat + description:Infinite missiles + code:SZKUANVK + cheat + description:Infinite smoke + code:VXELTVSE + cheat + description:Hit anywhere + code:AENOKIIP+AENOESTA+AESXEUYA+AEVOSIGZ+SXNONISA + cheat + description:Enemies die automatically + code:AAUEASTA+AESXEUYA+XVSZXLAV + cheat + description:No enemies + code:SXSOOZSA+SZUOVLSA + cheat + description:Double missiles on pick-up + code:TEEXLILA + cheat + description:Slow down timer + code:YAEZNIYE + cheat + description:Keep special weapons + code:GXSAKUSE+GXSANUSE + cheat + description:Start with 2 extra lives + code:ZEEXKIAA + cheat + description:Start with 6 extra lives + code:TEEXKIAA + +cartridge sha256:91c61066a9b6b5ed169449b175190d75d38834e07da263f637af05801bc2f5ae + title:Spy vs Spy (USA) + cheat + description:Stop black spy's clock + code:SZVAYUVK + cheat + description:Stop white spy's clock + code:SXUELUVK + cheat + description:Black spy has 100 seconds in a minute + code:PUEAPLIU + cheat + description:White spy has 100 seconds in a minute + code:PUSAILIU + cheat + description:Black spy has deadly punches + code:ONVZYNUT + cheat + description:White spy has deadly punches + code:IEVZLYIE + +cartridge sha256:687963e7fd12834543da99c60a533fcdfedacd27f8a67c0c9c4007c1263a79b3 + title:Sqoon (USA) + cheat + description:Infinite lives + code:AEEAAIPA + cheat + description:Never lose your special weapon + code:SZEEOSVK + cheat + description:Never lose humans on dying + code:GXEAKKSE+GXSUZXSE + cheat + description:Gain main weapon on rescuing 9 humans + code:ZEOOEYPA + cheat + description:Start with 1 life + code:AEUESLZA + cheat + description:Start with 6 lives + code:IEUESLZA + cheat + description:Start with 9 lives + code:AEUESLZE + cheat + description:Start at phase 3 + code:LASEXLPA + cheat + description:Start at phase 5 + code:IASEXLPA + cheat + description:Start at phase 8 + code:AASEXLPE + +cartridge sha256:b2e222df4d50fb75b108eac25e2beb671e37881bb357aa89bde7ef73d8d670f2 + title:Squashed (USA) (Proto) + cheat + description:Invincibility + code:SXOOZTAX + cheat + description:Infinite lives + code:SINPTKVS + cheat + description:Infinite time + code:SGVTIVVK + +cartridge sha256:d9a666f7b122bff2db329d346e20d9708ad58471ea80fbd032aa4600e86ad8f1 + title:Stanley - The Search for Dr. Livingston (USA) + cheat + description:Infinite health + code:SZEGYUSE + cheat + description:Infinite time on continue screen + code:XTSXXYVK + cheat + description:Start a new game with complete map + code:NNXGVZAE + cheat + description:Infinite health (alt) + code:057E:26 + cheat + description:Have all weapons + code:049E:5F+049D:5F+049C:5F+049B:5F+049A:5F+0499:5F+0498:01+0497:5F+0496:5F + +cartridge sha256:581851e22e8d499ada19e621c93571fba279fe9c8446ed2ee566b16128f13874 + title:Star Force (USA) + cheat + description:Infinite lives + code:SZKEVTVG + cheat + description:Turbo speed + code:VYVEGONN + cheat + description:Start with 1 life + code:AEUAUIZA + cheat + description:Start with 6 lives + code:IEUAUIZA + cheat + description:Start with 9 lives + code:AEUAUIZE + +cartridge sha256:7b7ccdcda705c2c3215c646b479c5d5868b72f3cd3eff97291d608756e5f3230 + title:Starship Hector (USA) + cheat + description:Take minimum damage + code:OVUYEGSV+PEUYOGTA + cheat + description:Infinite lives + code:SZKIOGVG + cheat + description:Extra health from capsules + code:GEVVGIPA + cheat + description:Start with 1 life + code:AANSOGZA + cheat + description:Start with 6 lives + code:IANSOGZA + cheat + description:Start with 9 lives + code:AANSOGZE + cheat + description:Start at stage 2 + code:PENYGIAA + cheat + description:Start at stage 3 + code:ZENYGIAA + cheat + description:Start at stage 4 + code:LENYGIAA + cheat + description:Start at stage 5 + code:GENYGIAA + cheat + description:Infinite health + code:00B0:10 + cheat + description:Play as Bomberking + code:005F:01 + +cartridge sha256:025abe5ae4e1610fac2507296184f64173fd960adfc79d456001adec29c546a5 + title:Star Soldier (USA) + cheat + description:Infinite lives + code:SZOEAPVG + cheat + description:Infinite shield power + code:GXVPXTVG + cheat + description:Double shield power + code:ZAOOOYIE+ZENOGLIE + cheat + description:Start with laser + code:PEOAPPAA + +cartridge sha256:a3d132f118c0d95590579c6d6b89b6bbe448a93aab93b3a29490f985b821a42c + title:Star Trek - 25th Anniversary (USA) + cheat + description:Kirk has more energy + code:LEOOVGYE + cheat + description:Kirk has less energy + code:GEOOVGYA + cheat + description:McCoy has more energy + code:LAUXYAYE + cheat + description:McCoy has less energy + code:GAUXYAYA + cheat + description:Spock has more energy + code:LAUZTAYE + cheat + description:Spock has less energy + code:GAUZTAYA + cheat + description:Security has more energy + code:LAVZLAYE + cheat + description:Geologist has more energy + code:LAKXAAYE + cheat + description:Geologist has less energy + code:GAKXAAYA + cheat + description:Biologist has more energy + code:LASXZAYE + cheat + description:Biologist has less energy + code:GASXZAYA + cheat + description:Historian has more energy + code:LASZPAYE + cheat + description:Historian has less energy + code:GASZPAYA + cheat + description:McCoy gives full energy to injured party + code:YEKUYPGA + +cartridge sha256:8271542561a71830886e88ac74e6eda309440920b3607e950d5f2cd1a7edd5ca + title:Star Trek - The Next Generation (USA) + cheat + description:All systems are immune to damage - shields down + code:OUXTPYOP + cheat + description:Shields are immune to damage - shields up + code:SXUVTNSE + cheat + description:Quicker damage repair + code:AGKVTTEP + cheat + description:Very quick damage repair + code:APKVTTEP + cheat + description:Slower damage repair + code:EGKVTTEP + cheat + description:Enemy does less damage + code:ZKNVLEZE + cheat + description:Stop game time ticking over + code:ATETISVT + cheat + description:Photon Torpedoes always work + code:AAUZPAGY + cheat + description:Phasers always work + code:AAEXTPNY + cheat + description:Phasers fire for longer + code:AAOXPOKT + cheat + description:Damage is repaired immediately + code:AAVTZVIL + cheat + description:Transporter power does not decrease most of the time + code:SXVUSTVG + cheat + description:Less transporter power required most of the time + code:IANUXTAZ + cheat + description:Stardate does not advance + code:GVNZOZIT + +cartridge sha256:2e366cb5ebcce2cd7be431b84bbbb401104e2717322b15e5368707b4eddeb11a + title:Star Trek V - The Final Frontier (Unknown) (Proto) + cheat + description:Invincibility (blinking) + code:EINONZEY + cheat + description:Infinite health + code:SZEPYSSE+SZNAXOSE + cheat + description:Infinite Phasers + code:SXOPVSSE + cheat + description:Infinite Bombs + code:SXNXLXVK + +cartridge sha256:69de2c7552fa81ca5921da0e457abf1be35f18ffbad159788a76141be59c9f6b + title:StarTropics (USA) + cheat + description:Infinite health + code:VZVZLOSV + cheat + description:Infinite lives + code:SXETAKVK + cheat + description:Infinite weapons + code:SUXXPSVS + cheat + description:Enemies can't move + code:NOPSTU + cheat + description:1 star needed to restore health + code:PEXXYTIA+PEUZLTIA + cheat + description:9 stars needed to restore health + code:PEXXYTIE+PEUZLTIE + cheat + description:1 life with a new character + code:PASTYZLA + cheat + description:6 lives with a new character + code:TASTYZLA + cheat + description:1 life after continue + code:PAUTGILA + cheat + description:6 lives after continue + code:TAUTGILA + cheat + description:Gain 50 fire weapons on pick-up + code:ZUVLZEPP + cheat + description:Gain 50 bat weapons on pick-up + code:ZUSUYETP + cheat + description:Only 3 hearts needed to use shooting-star + code:IEUZZNGA + cheat + description:Only 8 hearts needed to use super-nova + code:AEOZPYTO + cheat + description:Invincibility after one hit + code:077B:2E + cheat + description:Infinite health (alt) + code:0112:17 + cheat + description:Infinite Blue Stars + code:011C:09 + cheat + description:Permanent Anklet (can jump 2 spaces) + code:005B:02+0180:01 + +cartridge sha256:c4c139d2c349a513d4ccc724daee3fd37099c3c0d2742fad777a0edbe3d042ce + title:Star Voyager (USA) + cheat + description:Infinite life support pods + code:GZSZSTVG + cheat + description:Start with double life support pods + code:GPKIASZA + cheat + description:Start with triple life support pods + code:TPKIASZE + cheat + description:Barrier won't take damage + code:AASLSLLA + cheat + description:Radar won't take damage + code:AOKLVLEI + cheat + description:Cannon won't take damage + code:ENXLXLEI + cheat + description:Engine won't take damage + code:AAXUXLLA + +cartridge sha256:b9116f11828e39d3e201c878a874f0d88fa0eae9dece0469bf94a7e9c8616775 + title:Star Wars (USA) + cheat + description:Infinite lives + code:SZEAYXVK + cheat + description:Immune to spikes, you can get stuck on them + code:GZSYLSSO + cheat + description:Immune to most bullets + code:SLVUYNSO + cheat + description:Immune to most collisions + code:GXNUZIST+SLKLYVSO + cheat + description:Full energy on big energy pick-ups + code:AAKLNGZA + cheat + description:Less energy on big energy pick-ups + code:AAKLUGAX + cheat + description:More energy on big energy pick-ups + code:AGKLUGAZ + cheat + description:Always running + code:ZEOKOIPA+ZEKKXIPA + cheat + description:Start with 1 life + code:AAXAGAZA + cheat + description:Start with 6 lives + code:IAXAGAZA + cheat + description:Start with 9 lives + code:AAXAGAZE + +cartridge sha256:01b1bc93f72286a10ac62869ebe1bf2493ca24b3386e01447b0ccac50acdee94 + title:Star Wars - The Empire Strikes Back (USA) + cheat + description:Don't take damage from most enemies + code:GZVZTNOO + cheat + description:9 harpoons - scene 2 + code:PESZYPIE + cheat + description:1 harpoons - scene 2 + code:PESZYPIA + cheat + description:Infinite harpoons - scene 2 + code:GZVZVKVK + cheat + description:Infinite energy for ship - scene 2 + code:GXSLIISA + cheat + description:Always have Lightsaber + code:AEXOETYL + cheat + description:Start with 14 continues + code:TENLGIYE + cheat + description:Start on scene 2 + code:PAEGXLAA + cheat + description:Start on scene 3 + code:ZAEGXLAA + cheat + description:Start on scene 4 + code:LAEGXLAA + cheat + description:Start on scene 5 + code:GAEGXLAA + cheat + description:Start on scene 6 + code:IAEGXLAA + cheat + description:Start on scene 7 + code:TAEGXLAA + +cartridge sha256:8093144834f1153e95076a76dbc720cec37a31412b422c8adf9f5bcea1b642e8 + title:Stealth ATF (USA) + cheat + description:Infinite missiles + code:SZVZSSVK + cheat + description:Start with double missiles + code:AOUXXEAA + cheat + description:No damage taken from enemy's bullets + code:SZVPXNVV + cheat + description:Start with less fuel + code:AVUXNAVP + cheat + description:More enemy planes on the screen + code:AEKZZLZE + +cartridge sha256:5ca7cb3c4168bb021a67b50fa071afe7679f4e79c5c46e229fbe7b88004bf51a + title:Stinger (USA) + cheat + description:Keep weapons after death + code:GZNGNLSP + cheat + description:Infinite lives + code:OZVKKLVS + cheat + description:Skip intro + code:IESKLLAA + cheat + description:Start with 1 life + code:PAXKPGLA + cheat + description:Start with 6 lives + code:TAXKPGLA + cheat + description:Start with 9 lives + code:PAXKPGLE + cheat + description:Start with Dual Cannons + code:YGNGAKTL+PAVKTGAP + cheat + description:Start with Laser + code:YGNGAKTL+ZAVKTGAP + cheat + description:Start with Shoot Right + code:YGNGAKTL+GAVKTGAP + cheat + description:Start with Shoot Left + code:YGNGAKTL+AAVKTGAO + cheat + description:Start with Five Direction Firing + code:YGNGAKTL+APVKTGAP + cheat + description:Start with Three Direction Firing + code:YGNGAKTL+AZVKTGAP + cheat + description:Start with Force field + code:YGNGAKTL+AGVKTGAP + cheat + description:Start at stage 2 (wait for demo game then press start) + code:GZOGIGSA+PAEGPLPA + cheat + description:Start at stage 3 + code:GZOGIGSA+ZAEGPLPA + cheat + description:Start at stage 4 + code:GZOGIGSA+LAEGPLPA + cheat + description:Start at stage 5 + code:GZOGIGSA+GAEGPLPA + cheat + description:Start at stage 6 + code:GZOGIGSA+IAEGPLPA + cheat + description:Invincibility + code:0056:50 + cheat + description:Infinite lives (alt) + code:0038:09 + +cartridge sha256:d8a12772ddcb35d66a6518096c8415961cb43ceb9ffb96e5c7f83fe3a8e7f2c1 + title:Street Cop (USA) + cheat + description:Infinite health + code:GXESTZST + cheat + description:Take minimum damage + code:OVESTZSV+PEESYZAP + cheat + description:Infinite time + code:SZSNTAVG + cheat + description:Have less time + code:TAOVTXPA + cheat + description:Have more time + code:ZPOVTXPA + cheat + description:Start with less health + code:AONGNAAU + cheat + description:Start with more health + code:AVNGNAAL + cheat + description:Start at level 2 + code:PAXTPPAA + cheat + description:Start at level 3 + code:ZAXTPPAA + cheat + description:Start at level 4 + code:LAXTPPAA + +cartridge sha256:885cfd4396e0ade5f3abbbdb5055bc48ef166f86207db631bac83c51c0844f08 + title:Street Fighter 2010 - The Final Fight (USA) + cheat + description:Invincibility + code:EYSSLGEI + cheat + description:Infinite health + code:AEUIPGZA + cheat + description:Infinite lives + code:SZUATPVG + cheat + description:Infinite time + code:SLUKAZSP + cheat + description:Take less damage + code:PEUIPGZA + cheat + description:Take more damage + code:LEUIPGZA + cheat + description:Keep power-ups after losing a life + code:GZOAZPSA + cheat + description:Keep power-ups when hit + code:AEKIYGZA + cheat + description:Faster Ken + code:ZESESPPA + cheat + description:Portal always stays open + code:SXVTVUVK + cheat + description:Start with 1 life + code:AAEETAGA + cheat + description:Start with 9 lives + code:PAEETAGE + +cartridge sha256:07401bfb725c61711ce0a1d5eade14e09cd0f1b90991691339077a0b7dea5e58 + title:Street Heroes (Asia) (Unl) + cheat + description:Infinite health + code:00D6:59 + cheat + description:One hit kills + code:00D7:00 + cheat + description:Only one win needed to advance + code:0059:02 + +cartridge sha256:d4fc5610f1355c545d1ecf21502c31a9d21a31e0d4f0043c7c8d8f199bea2a73 + title:Strider (USA) + cheat + description:Infinite health + code:OXNAUKPX+PVNAVGIU + cheat + description:More energy from small capsules (10) + code:ZAUXEYPE + cheat + description:More energy from big capsules (20) + code:GPUXXNZA + cheat + description:Health from small capsules (10) + code:ZAUXKYPE + cheat + description:Health from big capsules (20) + code:GPUXVNZA + cheat + description:Double health and energy from all capsules + code:ZAEXVNAO + cheat + description:Have all Keys and start on Red Dragon level + code:048C:FF + cheat + description:Have all Data Files + code:048E:FF + cheat + description:Max stats, all tricks, Slide In, Plasma Arrow + code:048B:09+048D:01 + cheat + description:Infinite power + code:056B:63 + cheat + description:High-jump + code:0538:0A + cheat + description:Plasma Sword is instantly charged + code:055D:89 + +cartridge sha256:9aa6ced81adbfb09730591efa9aea369ec7bf57d8a1504dfd5f77ff5696b0427 + title:Strike Wolf (MGC-014) + cheat + description:Infinite energy + code:SZKUNISA + cheat + description:Infinite ammo + code:SZSONEVK + cheat + description:Infinite Bombs + code:SXXPLNVK + +cartridge sha256:f3a140c16012c4e4fb0deda64cbee7d9ebe78d2fb717b80b12a9f938d57b78bb + title:Stunt Kids (USA) (Unl) + cheat + description:Infinite time - P1 + code:SLNOYXVS + cheat + description:Infinite time - P2 + code:SLXOYUVS + cheat + description:Infinite lives + code:SZSZSKVK + cheat + description:Always have 9 coins after a race + code:VANILVKE + cheat + description:Coins worth nothing on pick-up + code:SZKOEOVV + cheat + description:Start with 1 life instead of 3 + code:AESGNZZA + cheat + description:Start with 6 lives + code:IESGNZZA + cheat + description:Start with 9 lives + code:PESGNZZE + cheat + description:Start with 0 turbos instead of 3 + code:AEESPALA + cheat + description:Start with 6 turbos + code:TEESPALA + cheat + description:Start with 9 turbos + code:PEESPALE + +cartridge sha256:4d16627301ff5def67247039b3a4b1cce4d20fbb867f4c5b7bcab43a8575f59f + title:Sunday Funday - The Ride (USA) (Unl) + cheat + description:Enable level skip (press B then Select) + code:ESNNUZEY + +cartridge sha256:3edd803db1cc88155720625ed8f3e362a5e3c660e7faf3285bbe3a2c6571511c + title:Super C (USA) + cheat + description:Invincibility - both players + code:LLLXZO + cheat + description:Infinite continues + code:SZOVXZVG + cheat + description:Activates 10 lives code + code:AEXVAIZA + cheat + description:10 lives code give you 30 + code:IOXVZSPE + cheat + description:Extra life for each enemy killed + code:AENTTTZA + cheat + description:Hit anywhere + code:POXXIOIA + cheat + description:One hit kills + code:AAAZPZ + cheat + description:Multi-jump - both players + code:GXVAATEI+ZUVEPVIV + cheat + description:Run faster to the right + code:EYYAEA + cheat + description:Stage select after title screen + code:ENXVYGEI + cheat + description:Press Start to complete current level + code:AUOVNXPU+GEOVSZPA + cheat + description:Start a new game to view the ending + code:AEKTLGAE + cheat + description:Start with Spray Gun + code:EUUTGIYS+YSXTPSEL+ZEUTZIAA + cheat + description:Start with Fireball Gun + code:EUUTGIYS+YSXTPSEL+GEUTZIAA + cheat + description:Start with 1 life - both players + code:AEXTLIZA + cheat + description:Start with 6 lives - both players + code:IEXTLIZA + cheat + description:Start with 9 lives - both players + code:AEXTLIZE + cheat + description:Start with 255 lives - both players + code:NNXTLIZE + cheat + description:Start with 9 continues + code:TEEVIIZA + cheat + description:Start at area 2 + code:PEETLIAA + cheat + description:Start at area 3 + code:ZEETLIAA + cheat + description:Start at area 4 + code:LEETLIAA + cheat + description:Start at area 5 + code:GEETLIAA + cheat + description:Start at area 6 + code:IEETLIAA + cheat + description:Start at area 7 + code:TEETLIAA + cheat + description:Invincibility (blinking) + code:00D4:55 + cheat + description:Infinite lives + code:0053:03 + cheat + description:Have the Machine Gun + code:00B8:81 + cheat + description:Have the Spread Gun + code:00B8:82 + cheat + description:Have the Laser Gun + code:00B8:83 + cheat + description:Have the Fireball Gun + code:00B8:84 + cheat + description:Have the Single Shot MG + code:00B8:85 + cheat + description:Have the Super Fireball Gun + code:00B8:86 + +cartridge sha256:fcb6a0ef3a20c19b356005fbb21dc8009563b1cb5a9aaebc8e9386b4a8c5912e + title:Super Mario Bros. (World) + cheat + description:Invincibility + code:SEVVOVSX+ESVVKTEY + cheat + description:Invincibility (Starman effect) + code:SSASSA + cheat + description:Infinite time + code:VZTLTN + cheat + description:Infinite time (alt) + code:SZTLTN + cheat + description:Infinite lives - both players + code:SXIOPO + cheat + description:Infinite lives + code:SKSOPOVK + cheat + description:Always Big Mario + code:OZTLLX+AATLGZ+SZLIVO + cheat + description:Always Fiery Mario + code:ZZZLTT + cheat + description:Always get 3 fireworks at end of stage + code:GPAIIU + cheat + description:Always get 6 fireworks at end of stage + code:VENITZYA + cheat + description:After falling down a hole, you drop from above + code:OXNLUYSO + cheat + description:Fireballs hit anywhere + code:GZXIPYEP + cheat + description:Gain a 1-up when an enemy is killed or power-up is gained + code:AEVAIGYA + cheat + description:Goombas don't walk off ledges + code:LETTTE + cheat + description:Mega-jump from a standing start only + code:APZLGG + cheat + description:Mega-jump from running only + code:APZLTG + cheat + description:Mega-jump from turbo running only + code:GAZUAG + cheat + description:Moon Gravity from a standing start + code:YAZULG + cheat + description:Moon Gravity from a running start + code:YAZUIG + cheat + description:Moon Gravity from turbo running only + code:YAZUYG + cheat + description:Multi-jump + code:AOAUIG + cheat + description:Super-jump from a standing start only + code:APZLGK + cheat + description:Super-jump from running only + code:TPZLTG + cheat + description:Super-jump from turbo running only + code:GPZUAG + cheat + description:Turn all enemies into Toad + code:NULTKA + cheat + description:Can control Mario in demo and title screen + code:PEUEGZAA+ANUETXKY+YEUEYZTA + cheat + description:Can control Mario in entrances that lead to underground + code:SNAULA + cheat + description:Can move left or right while crouched + code:APXLLPEY + cheat + description:Can walk through pipes and blocks + code:GIIIVY + cheat + description:Small Mario can break bricks + code:AAOUEIPA+AENLNGZA+EZOLNIEI + cheat + description:Fireballs can kill Bowser's Fire + code:AEOIGNTZ + cheat + description:Fireballs can kill Bullet Bill + code:AEESGYTL + cheat + description:Fireballs can kill Buzzy Beetle + code:AASIYNLT + cheat + description:Fireballs can kill Podoboo + code:AAXVZAGA+AEOIAYZL + cheat + description:Enable level select + code:AAYAAZ + cheat + description:Start with 1 life - both players + code:AATOZA + cheat + description:Start with 6 lives - both players + code:IATOZA + cheat + description:Start with 9 lives - both players + code:AATOZE + cheat + description:Start P1 with 8 lives and P2 with 3 lives + code:VATOLE + cheat + description:Start on World 2 + code:YSAOPE+YEAOZA+PEAPYA + cheat + description:Start on World 3 + code:YSAOPE+YEAOZA+ZEAPYA + cheat + description:Start on World 4 + code:YSAOPE+YEAOZA+LEAPYA + cheat + description:Start on World 5 + code:YSAOPE+YEAOZA+GEAPYA + cheat + description:Start on World 6 + code:YSAOPE+YEAOZA+IEAPYA + cheat + description:Start on World 7 + code:YSAOPE+YEAOZA+TEAPYA + cheat + description:Start on World 8 + code:YSAOPE+YEAOZA+YEAPYA + cheat + description:Invincibility (blinking) + code:079E:06 + cheat + description:Invincibility (Starman effect) (alt) + code:079F:18 + cheat + description:Infinite lives (alt) + code:075A:09 + cheat + description:Infinite time (alt 2) + code:0787:0C + cheat + description:Always Big Mario (alt) + code:0754:00+0756:01 + cheat + description:Always Fiery Mario (alt) + code:0754:00+0756:02 + +cartridge sha256:5dde385041aa7364c78205f2ba49615f416c701b6025e38aa1d7b9c4f99a62db + title:Super Mario Bros. + Duck Hunt (USA) + cheat + description:DH - Infinite ammo + code:SZNIPPVG + cheat + description:DH - Hit anywhere + code:AAXSGZSY + cheat + description:DH - Always get the perfect bonus + code:AASIAUZA+ALSIPLEI + cheat + description:DH - Ducks never fly away - Game A + code:IAVKKZVG + cheat + description:DH - Enable game "D" (press Select three times) + code:GEOKTPLA + cheat + description:SMB - Invincibility + code:SEVVOVSX+ESVVKTEY + cheat + description:SMB - Invincibility (Starman effect) + code:SSASSA + cheat + description:SMB - Infinite time + code:VZTLTN + cheat + description:SMB - Infinite time (alt) + code:SZTLTN + cheat + description:SMB - Infinite lives - both players + code:SXIOPO + cheat + description:SMB - Infinite lives + code:SKSOPOVK + cheat + description:SMB - Always Big Mario + code:OZTLLX+AATLGZ+SZLIVO + cheat + description:SMB - Always Fiery Mario + code:ZZZLTT + cheat + description:SMB - Always get 3 fireworks at end of stage + code:GPAIIU + cheat + description:SMB - Always get 6 fireworks at end of stage + code:VENITZYA + cheat + description:SMB - After falling down a hole, you drop from above + code:OXNLUYSO + cheat + description:SMB - Fireballs hit anywhere + code:GZXIPYEP + cheat + description:SMB - Gain a 1-up when an enemy is killed or power-up is gained + code:AEVAIGYA + cheat + description:SMB - Goombas don't walk off ledges + code:LETTTE + cheat + description:SMB - Mega-jump from a standing start only + code:APZLGG + cheat + description:SMB - Mega-jump from running only + code:APZLTG + cheat + description:SMB - Mega-jump from turbo running only + code:GAZUAG + cheat + description:SMB - Moon Gravity from a standing start + code:YAZULG + cheat + description:SMB - Moon Gravity from a running start + code:YAZUIG + cheat + description:SMB - Moon Gravity from turbo running only + code:YAZUYG + cheat + description:SMB - Multi-jump + code:AOAUIG + cheat + description:SMB - Super-jump from a standing start only + code:APZLGK + cheat + description:SMB - Super-jump from running only + code:TPZLTG + cheat + description:SMB - Super-jump from turbo running only + code:GPZUAG + cheat + description:SMB - Turn all enemies into Toad + code:NULTKA + cheat + description:SMB - Can control Mario in demo and title screen + code:PEUEGZAA+ANUETXKY+YEUEYZTA + cheat + description:SMB - Can control Mario in entrances that lead to underground + code:SNAULA + cheat + description:SMB - Can move left or right while crouched + code:APXLLPEY + cheat + description:SMB - Can walk through pipes and blocks + code:GIIIVY + cheat + description:SMB - Small Mario can break bricks + code:AAOUEIPA+AENLNGZA+EZOLNIEI + cheat + description:SMB - Fireballs can kill Bowser's Fire + code:AEOIGNTZ + cheat + description:SMB - Fireballs can kill Bullet Bill + code:AEESGYTL + cheat + description:SMB - Fireballs can kill Buzzy Beetle + code:AASIYNLT + cheat + description:SMB - Fireballs can kill Podoboo + code:AAXVZAGA+AEOIAYZL + cheat + description:SMB - Enable level select + code:AAYAAZ + cheat + description:SMB - Start with 1 life - both players + code:AATOZA + cheat + description:SMB - Start with 6 lives - both players + code:IATOZA + cheat + description:SMB - Start with 9 lives - both players + code:AATOZE + cheat + description:SMB - Start P1 with 8 lives and P2 with 3 lives + code:VATOLE + cheat + description:SMB - Start on World 2 + code:YSAOPE+YEAOZA+PEAPYA + cheat + description:SMB - Start on World 3 + code:YSAOPE+YEAOZA+ZEAPYA + cheat + description:SMB - Start on World 4 + code:YSAOPE+YEAOZA+LEAPYA + cheat + description:SMB - Start on World 5 + code:YSAOPE+YEAOZA+GEAPYA + cheat + description:SMB - Start on World 6 + code:YSAOPE+YEAOZA+IEAPYA + cheat + description:SMB - Start on World 7 + code:YSAOPE+YEAOZA+TEAPYA + cheat + description:SMB - Start on World 8 + code:YSAOPE+YEAOZA+YEAPYA + cheat + description:DH - Infinite ammo (alt) + code:00BA:03 + cheat + description:SMB - Invincibility (blinking) + code:079E:06 + cheat + description:SMB - Invincibility (Starman effect) (alt) + code:079F:18 + cheat + description:SMB - Infinite lives (alt) + code:075A:09 + cheat + description:SMB - Infinite time (alt 2) + code:0787:0C + cheat + description:SMB - Always Big Mario (alt) + code:0754:00+0756:01 + cheat + description:SMB - Always Fiery Mario (alt) + code:0754:00+0756:02 + +cartridge sha256:26977a6c51a6f1e1af895b8863e8e7d57c5321621f29cf58ebfbf85163a999dd + title:Super Mario Bros. + Duck Hunt + World Class Track Meet (USA) (Rev A) + cheat + description:DH - Infinite ammo + code:SZNIPPVG + cheat + description:DH - Hit anywhere + code:AAXSGZSY + cheat + description:DH - Always get the perfect bonus + code:AASIAUZA+ALSIPLEI + cheat + description:DH - Ducks never fly away - Game A + code:IAVKKZVG + cheat + description:DH - Enable game "D" (press Select three times) + code:GEOKTPLA + cheat + description:SMB - Invincibility + code:SEVVOVSX+ESVVKTEY + cheat + description:SMB - Invincibility (Starman effect) + code:SSASSA + cheat + description:SMB - Infinite time + code:VZTLTN + cheat + description:SMB - Infinite time (alt) + code:SZTLTN + cheat + description:SMB - Infinite lives - both players + code:SXIOPO + cheat + description:SMB - Infinite lives + code:SKSOPOVK + cheat + description:SMB - Always Big Mario + code:OZTLLX+AATLGZ+SZLIVO + cheat + description:SMB - Always Fiery Mario + code:ZZZLTT + cheat + description:SMB - Always get 3 fireworks at end of stage + code:GPAIIU + cheat + description:SMB - Always get 6 fireworks at end of stage + code:VENITZYA + cheat + description:SMB - After falling down a hole, you drop from above + code:OXNLUYSO + cheat + description:SMB - Fireballs hit anywhere + code:GZXIPYEP + cheat + description:SMB - Gain a 1-up when an enemy is killed or power-up is gained + code:AEVAIGYA + cheat + description:SMB - Goombas don't walk off ledges + code:LETTTE + cheat + description:SMB - Mega-jump from a standing start only + code:APZLGG + cheat + description:SMB - Mega-jump from running only + code:APZLTG + cheat + description:SMB - Mega-jump from turbo running only + code:GAZUAG + cheat + description:SMB - Moon Gravity from a standing start + code:YAZULG + cheat + description:SMB - Moon Gravity from a running start + code:YAZUIG + cheat + description:SMB - Moon Gravity from turbo running only + code:YAZUYG + cheat + description:SMB - Multi-jump + code:AOAUIG + cheat + description:SMB - Super-jump from a standing start only + code:APZLGK + cheat + description:SMB - Super-jump from running only + code:TPZLTG + cheat + description:SMB - Super-jump from turbo running only + code:GPZUAG + cheat + description:SMB - Turn all enemies into Toad + code:NULTKA + cheat + description:SMB - Can control Mario in demo and title screen + code:PEUEGZAA+ANUETXKY+YEUEYZTA + cheat + description:SMB - Can control Mario in entrances that lead to underground + code:SNAULA + cheat + description:SMB - Can move left or right while crouched + code:APXLLPEY + cheat + description:SMB - Can walk through pipes and blocks + code:GIIIVY + cheat + description:SMB - Small Mario can break bricks + code:AAOUEIPA+AENLNGZA+EZOLNIEI + cheat + description:SMB - Fireballs can kill Bowser's Fire + code:AEOIGNTZ + cheat + description:SMB - Fireballs can kill Bullet Bill + code:AEESGYTL + cheat + description:SMB - Fireballs can kill Buzzy Beetle + code:AASIYNLT + cheat + description:SMB - Fireballs can kill Podoboo + code:AAXVZAGA+AEOIAYZL + cheat + description:SMB - Enable level select + code:AAYAAZ + cheat + description:SMB - Start with 1 life - both players + code:AATOZA + cheat + description:SMB - Start with 6 lives - both players + code:IATOZA + cheat + description:SMB - Start with 9 lives - both players + code:AATOZE + cheat + description:SMB - Start P1 with 8 lives and P2 with 3 lives + code:VATOLE + cheat + description:SMB - Start on World 2 + code:YSAOPE+YEAOZA+PEAPYA + cheat + description:SMB - Start on World 3 + code:YSAOPE+YEAOZA+ZEAPYA + cheat + description:SMB - Start on World 4 + code:YSAOPE+YEAOZA+LEAPYA + cheat + description:SMB - Start on World 5 + code:YSAOPE+YEAOZA+GEAPYA + cheat + description:SMB - Start on World 6 + code:YSAOPE+YEAOZA+IEAPYA + cheat + description:SMB - Start on World 7 + code:YSAOPE+YEAOZA+TEAPYA + cheat + description:SMB - Start on World 8 + code:YSAOPE+YEAOZA+YEAPYA + cheat + description:DH - Infinite ammo (alt) + code:00BA:03 + cheat + description:SMB - Invincibility (blinking) + code:079E:06 + cheat + description:SMB - Invincibility (Starman effect) (alt) + code:079F:18 + cheat + description:SMB - Infinite lives (alt) + code:075A:09 + cheat + description:SMB - Infinite time (alt 2) + code:0787:0C + cheat + description:SMB - Always Big Mario (alt) + code:0754:00+0756:01 + cheat + description:SMB - Always Fiery Mario (alt) + code:0754:00+0756:02 + +cartridge sha256:968cf4ae63fddf6a0d379bb12add5563f468e57ddddb69e00e1379a839234f95 + title:Super Mario Bros. + Duck Hunt + World Class Track Meet (USA) + cheat + description:DH - Infinite ammo + code:SZNIPPVG + cheat + description:DH - Hit anywhere + code:AAXSGZSY + cheat + description:DH - Always get the perfect bonus + code:AASIAUZA+ALSIPLEI + cheat + description:DH - Ducks never fly away - Game A + code:IAVKKZVG + cheat + description:DH - Enable game "D" (press Select three times) + code:GEOKTPLA + cheat + description:SMB - Invincibility + code:SEVVOVSX+ESVVKTEY + cheat + description:SMB - Invincibility (Starman effect) + code:SSASSA + cheat + description:SMB - Infinite time + code:VZTLTN + cheat + description:SMB - Infinite time (alt) + code:SZTLTN + cheat + description:SMB - Infinite lives - both players + code:SXIOPO + cheat + description:SMB - Infinite lives + code:SKSOPOVK + cheat + description:SMB - Always Big Mario + code:OZTLLX+AATLGZ+SZLIVO + cheat + description:SMB - Always Fiery Mario + code:ZZZLTT + cheat + description:SMB - Always get 3 fireworks at end of stage + code:GPAIIU + cheat + description:SMB - Always get 6 fireworks at end of stage + code:VENITZYA + cheat + description:SMB - After falling down a hole, you drop from above + code:OXNLUYSO + cheat + description:SMB - Fireballs hit anywhere + code:GZXIPYEP + cheat + description:SMB - Gain a 1-up when an enemy is killed or power-up is gained + code:AEVAIGYA + cheat + description:SMB - Goombas don't walk off ledges + code:LETTTE + cheat + description:SMB - Mega-jump from a standing start only + code:APZLGG + cheat + description:SMB - Mega-jump from running only + code:APZLTG + cheat + description:SMB - Mega-jump from turbo running only + code:GAZUAG + cheat + description:SMB - Moon Gravity from a standing start + code:YAZULG + cheat + description:SMB - Moon Gravity from a running start + code:YAZUIG + cheat + description:SMB - Moon Gravity from turbo running only + code:YAZUYG + cheat + description:SMB - Multi-jump + code:AOAUIG + cheat + description:SMB - Super-jump from a standing start only + code:APZLGK + cheat + description:SMB - Super-jump from running only + code:TPZLTG + cheat + description:SMB - Super-jump from turbo running only + code:GPZUAG + cheat + description:SMB - Turn all enemies into Toad + code:NULTKA + cheat + description:SMB - Can control Mario in demo and title screen + code:PEUEGZAA+ANUETXKY+YEUEYZTA + cheat + description:SMB - Can control Mario in entrances that lead to underground + code:SNAULA + cheat + description:SMB - Can move left or right while crouched + code:APXLLPEY + cheat + description:SMB - Can walk through pipes and blocks + code:GIIIVY + cheat + description:SMB - Small Mario can break bricks + code:AAOUEIPA+AENLNGZA+EZOLNIEI + cheat + description:SMB - Fireballs can kill Bowser's Fire + code:AEOIGNTZ + cheat + description:SMB - Fireballs can kill Bullet Bill + code:AEESGYTL + cheat + description:SMB - Fireballs can kill Buzzy Beetle + code:AASIYNLT + cheat + description:SMB - Fireballs can kill Podoboo + code:AAXVZAGA+AEOIAYZL + cheat + description:SMB - Enable level select + code:AAYAAZ + cheat + description:SMB - Start with 1 life - both players + code:AATOZA + cheat + description:SMB - Start with 6 lives - both players + code:IATOZA + cheat + description:SMB - Start with 9 lives - both players + code:AATOZE + cheat + description:SMB - Start P1 with 8 lives and P2 with 3 lives + code:VATOLE + cheat + description:SMB - Start on World 2 + code:YSAOPE+YEAOZA+PEAPYA + cheat + description:SMB - Start on World 3 + code:YSAOPE+YEAOZA+ZEAPYA + cheat + description:SMB - Start on World 4 + code:YSAOPE+YEAOZA+LEAPYA + cheat + description:SMB - Start on World 5 + code:YSAOPE+YEAOZA+GEAPYA + cheat + description:SMB - Start on World 6 + code:YSAOPE+YEAOZA+IEAPYA + cheat + description:SMB - Start on World 7 + code:YSAOPE+YEAOZA+TEAPYA + cheat + description:SMB - Start on World 8 + code:YSAOPE+YEAOZA+YEAPYA + cheat + description:DH - Infinite ammo (alt) + code:00BA:03 + cheat + description:SMB - Invincibility (blinking) + code:079E:06 + cheat + description:SMB - Invincibility (Starman effect) (alt) + code:079F:18 + cheat + description:SMB - Infinite lives (alt) + code:075A:09 + cheat + description:SMB - Infinite time (alt 2) + code:0787:0C + cheat + description:SMB - Always Big Mario (alt) + code:0754:00+0756:01 + cheat + description:SMB - Always Fiery Mario (alt) + code:0754:00+0756:02 + +cartridge sha256:728d0ca6751b0c039fc3e34f2e7f27a870afcab30f5e270244ac40979c5f69ca + title:Super Mario Bros. 2 (USA) (Rev A) + cheat + description:Invincibility + code:OZXYGLES+SAXYTLSZ + cheat + description:Infinite health (except if you hit a spike) + code:GZELVXSE + cheat + description:Infinite health (alt) + code:SZELVXSE + cheat + description:Infinite lives + code:SZNESXVK + cheat + description:All characters can float + code:ANNEEGEY + cheat + description:More sub-space time + code:YPZOTN + cheat + description:Quick pick-up + code:SXUASXOU + cheat + description:Infinite magic carpet time + code:SLNZZLVI + cheat + description:Jump as high as a squat jump + code:AEUEKKGL + cheat + description:Princess has mega-float + code:PPXAOIAA + cheat + description:Princess has mega-float and lunar descent + code:PAXAOIAA + cheat + description:Super moon-jumps - Mario + code:PESEGLGA + cheat + description:Mega moon-jumps - Luigi + code:AAEEZGPA + cheat + description:Super moon-jumps - Toad + code:PENALLGA + cheat + description:Super moon-jumps - Princess + code:PAXAPGGA + cheat + description:Speed up enemies + code:AEXALGZA + cheat + description:Super speed enemies + code:AXNAZSAA+EVNALSEY + cheat + description:Walk backwards + code:GOEANKAO+USEEEKKA + cheat + description:Super turbo running + code:XVVANSZK+XVNEXSZV + cheat + description:Permanent turbo running + code:AEVAVIIA+AENEEITA + cheat + description:Fast run - Toad + code:AXNAIUAO+ESNEAUEV + cheat + description:Super fast run - Mario + code:AXSETUAO+ESVAPUEV + cheat + description:Super fast run - Luigi + code:AZEEGKAO+EIEEYKEV + cheat + description:Super fast run - Princess + code:AZXALKAO+EIXATKEV + cheat + description:Weak Birdo + code:AAVENYZA + cheat + description:Strong Birdo + code:IAVENYZE + cheat + description:Strong Wart + code:YESUAPTE + cheat + description:Birdo spits eggs instead of fireballs (in late levels of the game) + code:TPEPLAAX + cheat + description:Start on World 2 + code:PEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 3 + code:ZEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 4 + code:LEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 5 + code:GEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 6 + code:IEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 7 + code:TEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Invincibility (alt) + code:0085:FA + cheat + description:Infinite coins + code:062B:09 + cheat + description:Infinite sub-space time + code:04B7:FA + cheat + description:Infinite magic carpet time (alt) + code:00B9:FA + cheat + description:All characters can float (alt) + code:04C9:FA + cheat + description:Multi-jump + code:0099:00 + cheat + description:One hit kills on bosses + code:0468:00 + cheat + description:Only 1 Cherry needed for Starman + code:062A:04 + cheat + description:Only 1 big Radish needed for Stopwatch + code:062C:04 + cheat + description:Receive small heart for every enemy defeated + code:04AD:09 + cheat + description:Stopwatch always active + code:04FF:FA + cheat + description:Start on World 2 (alt) + code:0635:01 + cheat + description:Start on World 3 (alt) + code:0635:02 + cheat + description:Start on World 4 (alt) + code:0635:03 + cheat + description:Start on World 5 (alt) + code:0635:04 + cheat + description:Start on World 6 (alt) + code:0635:05 + cheat + description:Start on World 7 (alt) + code:0635:06 + +cartridge sha256:cba920f9394733c82253685d7783f26a3033ba58a94623e9abf7892329b969b9 + title:Super Mario Bros. 2 (USA) + cheat + description:Invincibility + code:OZXYGLES+SAXYTLSZ + cheat + description:Infinite health (except if you hit a spike) + code:GZELVXSE + cheat + description:Infinite health (alt) + code:SZELVXSE + cheat + description:Infinite lives + code:SZNESXVK + cheat + description:Quick pick-up + code:SXUASXOU + cheat + description:Jump as high as a squat jump + code:AEUEKKGL + cheat + description:Princess has mega-float + code:PPXAOIAA + cheat + description:Princess has mega-float and lunar descent + code:PAXAOIAA + cheat + description:Super moon-jumps - Mario + code:PESEGLGA + cheat + description:Mega moon-jumps - Luigi + code:AAEEZGPA + cheat + description:Super moon-jumps - Toad + code:PENALLGA + cheat + description:Super moon-jumps - Princess + code:PAXAPGGA + cheat + description:Speed up enemies + code:AEXALGZA + cheat + description:Super speed enemies + code:AXNAZSAA+EVNALSEY + cheat + description:Walk backwards + code:GOEANKAO+USEEEKKA + cheat + description:Super turbo running + code:XVVANSZK+XVNEXSZV + cheat + description:Permanent turbo running + code:AEVAVIIA+AENEEITA + cheat + description:Fast run - Toad + code:AXNAIUAO+ESNEAUEV + cheat + description:Super fast run - Mario + code:AXSETUAO+ESVAPUEV + cheat + description:Super fast run - Luigi + code:AZEEGKAO+EIEEYKEV + cheat + description:Super fast run - Princess + code:AZXALKAO+EIXATKEV + cheat + description:Hawkeye at end of level always open + code:GXUESIEY + cheat + description:Start on World 2 + code:PEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 3 + code:ZEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 4 + code:LEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 5 + code:GEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 6 + code:IEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Start on World 7 + code:TEEPUZAG+IUEPSZAA+TEEPVZPA + cheat + description:Invincibility (alt) + code:0085:FA + cheat + description:Infinite coins + code:062B:09 + cheat + description:Infinite sub-space time + code:04B7:FA + cheat + description:Infinite magic carpet time (alt) + code:00B9:FA + cheat + description:All characters can float (alt) + code:04C9:FA + cheat + description:Multi-jump + code:0099:00 + cheat + description:One hit kills on bosses + code:0468:00 + cheat + description:Only 1 Cherry needed for Starman + code:062A:04 + cheat + description:Only 1 big Radish needed for Stopwatch + code:062C:04 + cheat + description:Receive small heart for every enemy defeated + code:04AD:09 + cheat + description:Stopwatch always active + code:04FF:FA + cheat + description:Start on World 2 (alt) + code:0635:01 + cheat + description:Start on World 3 (alt) + code:0635:02 + cheat + description:Start on World 4 (alt) + code:0635:03 + cheat + description:Start on World 5 (alt) + code:0635:04 + cheat + description:Start on World 6 (alt) + code:0635:05 + cheat + description:Start on World 7 (alt) + code:0635:06 + +cartridge sha256:ff8afb9ae6b705b4e51dbcb193dcebadf4c049800a71003d3a45052648e52eda + title:Super Mario Brothers 2 (Japan) (FDS) + cheat + description:Start with 50 lives + code:PUTGGI + cheat + description:Start with 9 lives + code:AETGGS + cheat + description:Invincibility (Starman effect) + code:079F:09 + cheat + description:Infinite lives + code:701B:AD + +cartridge sha256:959fdd32c71735d6fb2bd16a646d39f4ee65623273dd035e6a968e991bd13ef8 + title:Super Mario Bros. 3 (USA) (Rev A) + cheat + description:Invincibility (Starman effect) + code:AEVGEVZZ + cheat + description:Invincibility after changing up from Super Mario (Raccoon, Frog, ect.) + code:SZKIKXSE + cheat + description:Invincibility as miniture stone Mario + code:EXKXGLIA + cheat + description:Never die from being hit while little (changes music) (PRG0 only) + code:GOZSXX + cheat + description:Invincibility as Super Mario + code:XUKXGLIE + cheat + description:Invincibility as Fire Mario + code:UXKXGLIA + cheat + description:Invincibility as Raccoon Mario + code:NXKXGLIE + cheat + description:Invincibility as Frog Mario + code:OUKXGLIE + cheat + description:Invincibility as Sledgehammer Mario + code:XNKXGLIE + cheat + description:Infinite lives - both players + code:SLXPLOVS + cheat + description:Infinite time + code:SXUZENVK + cheat + description:Infinite items - Mario + code:YPXXLVGE + cheat + description:Always get a White Ship after passing a level + code:LGNXKGPL + cheat + description:Fireballs hit anywhere + code:AEXZAVUG+AEXXYVIG + cheat + description:Tail hits anywhere + code:GZSSOLEP + cheat + description:1 life after continue - both players + code:AEKPTZGA + cheat + description:9 lives after continue - both players + code:AEKPTZGE + cheat + description:1-up for each coin + code:PEEULAGT+PEOLAAGT + cheat + description:Change to Super Mario if you fall off screen and die + code:AEOSSZPA+PAOZTGAA + cheat + description:Change to Fire Mario if you fall off screen and die + code:AEOSSZPA+ZAOZTGAA + cheat + description:Change to Raccoon Mario if you fall off screen and die + code:AEOSSZPA+LAOZTGAA + cheat + description:Change to Frog Mario if you fall off screen and die + code:AEOSSZPA+GAOZTGAA + cheat + description:Change to Tanooki Mario if you fall off screen and die + code:AEOSSZPA+IAOZTGAA + cheat + description:Change to Sledgehammer Mario if you fall off screen and die + code:AEOSSZPA+TAOZTGAA + cheat + description:Move anywhere on the map + code:OXKIPZOS+APKSALAZ + cheat + description:Multi-jump + code:SXEZSKOZ + cheat + description:Multi-jump (alt) + code:SXEZSKOX + cheat + description:Multi-jump (alt 2) + code:GZUXNGEI + cheat + description:Power-jumps + code:ELKZYVEK + cheat + description:Super power-jumps + code:EZKZYVEK + cheat + description:Mega power-jumps + code:EAKZYVEK + cheat + description:Super speed running + code:OXKZELSX + cheat + description:Turbo-charged running + code:XVUXNUEE + cheat + description:Raise P meter while standing still (hold B) + code:AANZKLLA + cheat + description:Restore powers after playing an action scene + code:SZUEXNSO + cheat + description:Start a new game as Fire Mario + code:ZEUXKGAA + cheat + description:Start a new game as Raccoon Mario + code:LEUXKGAA + cheat + description:Start a new game as Frog Mario + code:GEUXKGAA + cheat + description:Start a new game as Tanooki Mario + code:IEUXKGAA + cheat + description:Start a new game as Sledgehammer Mario + code:TEUXKGAA + cheat + description:Start a new game to see the ending + code:NKGZSO + cheat + description:Start on World 2 + code:PEUZUGAA + cheat + description:Start on World 3 + code:ZEUZUGAA + cheat + description:Start on World 4 + code:LEUZUGAA + cheat + description:Start on World 5 + code:GEUZUGAA + cheat + description:Start on World 6 + code:IEUZUGAA + cheat + description:Start on World 7 + code:TEUZUGAA + cheat + description:Start on World 8 + code:YEUZUGAA + cheat + description:Unused level - Plains 1 + code:GGNUGGXE+NZNUIKUL + cheat + description:Unused level - Plains 2 + code:KZNUGGXE+OZNUIKUL + cheat + description:Unused level - Dungeon + code:ZZXUAGPZ+GINUGGXA+NLNUIKUL + cheat + description:Unused level - Underground 2 + code:LZXUAGPZ+ZGNUGGXA+KLNUIKUL + cheat + description:Unused level - Sky 1 + code:GZXUAGPZ+SGNUGGXE+SZNUIKUU + cheat + description:Unused level - Sky 3 (level cannot be completed) + code:GZXUAGPZ+KGNUGGXA+ELNUIKUL + cheat + description:Unused level - Cloudy 1 + code:IZXUAGPX+OZNUGGXE+KZNUIKUU + cheat + description:Unused level - Pipe level + code:AZXUAGPX+APNUGGXE+NZNUIKUU + cheat + description:Unused level - Hilly level + code:LZXUAGPZ+SINUGGXE+ELNUIKUL + cheat + description:Unused level - Ice/Water + code:GZXUAGPX+XLNUGGXE+NLNUIKUL + cheat + description:Unused level - Cloudy (level cannot be completed) + code:IZXUAGPX+UZNUGGXE+SZNUIKUU + cheat + description:P meter always full + code:03DD:7F + cheat + description:Invincibility as Super Mario (alt) + code:00ED:01 + cheat + description:Invincibility as Fire Mario (alt) + code:00ED:02 + cheat + description:Invincibility as Raccoon Mario (alt) + code:00ED:03 + cheat + description:Invincibility as Frog Mario (alt) + code:00ED:04 + cheat + description:Invincibility as Tanooki + code:00ED:05 + cheat + description:Invincibility as Sledgehammer Mario (alt) + code:00ED:06 + +cartridge sha256:d77d17d34af24871d7ce1160ccd3330555835c8e940b7100e095ac38973d927a + title:Super Mario Bros. 3 (USA) + cheat + description:Invincibility (Starman effect) + code:AEVGEVZZ + cheat + description:Invincibility after changing up from Super Mario (Raccoon, Frog, ect.) + code:SZKIKXSE + cheat + description:Invincibility as miniture stone Mario + code:EXKXGLIA + cheat + description:Never die from being hit while little (changes music) (PRG0 only) + code:GOZSXX + cheat + description:Invincibility as Super Mario + code:XUKXGLIE + cheat + description:Invincibility as Fire Mario + code:UXKXGLIA + cheat + description:Invincibility as Raccoon Mario + code:NXKXGLIE + cheat + description:Invincibility as Frog Mario + code:OUKXGLIE + cheat + description:Invincibility as Sledgehammer Mario + code:XNKXGLIE + cheat + description:Infinite lives - both players + code:SLXPLOVS + cheat + description:Infinite time + code:SXUZENVK + cheat + description:Infinite items - Mario + code:YPXXLVGE + cheat + description:Always get a White Ship after passing a level + code:LGNXKGPL + cheat + description:Fireballs hit anywhere + code:AEXZAVUG+AEXXYVIG + cheat + description:Tail hits anywhere + code:GZSSOLEP + cheat + description:1 life after continue - both players + code:AEKPTZGA + cheat + description:9 lives after continue - both players + code:AEKPTZGE + cheat + description:1-up for each coin + code:PEEULAGT+PEOLAAGT + cheat + description:Change to Super Mario if you fall off screen and die + code:AEOSSZPA+PAOZTGAA + cheat + description:Change to Fire Mario if you fall off screen and die + code:AEOSSZPA+ZAOZTGAA + cheat + description:Change to Raccoon Mario if you fall off screen and die + code:AEOSSZPA+LAOZTGAA + cheat + description:Change to Frog Mario if you fall off screen and die + code:AEOSSZPA+GAOZTGAA + cheat + description:Change to Tanooki Mario if you fall off screen and die + code:AEOSSZPA+IAOZTGAA + cheat + description:Change to Sledgehammer Mario if you fall off screen and die + code:AEOSSZPA+TAOZTGAA + cheat + description:Move anywhere on the map + code:OXKIPZOS+APKSALAZ + cheat + description:Multi-jump + code:SXEZSKOZ + cheat + description:Multi-jump (alt) + code:SXEZSKOX + cheat + description:Multi-jump (alt 2) + code:GZUXNGEI + cheat + description:Power-jumps + code:ELKZYVEK + cheat + description:Super power-jumps + code:EZKZYVEK + cheat + description:Mega power-jumps + code:EAKZYVEK + cheat + description:Super speed running + code:OXKZELSX + cheat + description:Turbo-charged running + code:XVUXNUEE + cheat + description:Raise P meter while standing still (hold B) + code:AANZKLLA + cheat + description:Restore powers after playing an action scene + code:SZUEXNSO + cheat + description:Start a new game as Fire Mario + code:ZEUXKGAA + cheat + description:Start a new game as Raccoon Mario + code:LEUXKGAA + cheat + description:Start a new game as Frog Mario + code:GEUXKGAA + cheat + description:Start a new game as Tanooki Mario + code:IEUXKGAA + cheat + description:Start a new game as Sledgehammer Mario + code:TEUXKGAA + cheat + description:Start a new game to see the ending + code:NKGZSO + cheat + description:Start on World 2 + code:PEUZUGAA + cheat + description:Start on World 3 + code:ZEUZUGAA + cheat + description:Start on World 4 + code:LEUZUGAA + cheat + description:Start on World 5 + code:GEUZUGAA + cheat + description:Start on World 6 + code:IEUZUGAA + cheat + description:Start on World 7 + code:TEUZUGAA + cheat + description:Start on World 8 + code:YEUZUGAA + cheat + description:Unused level - Plains 1 + code:GGNUGGXE+NZNUIKUL + cheat + description:Unused level - Plains 2 + code:KZNUGGXE+OZNUIKUL + cheat + description:Unused level - Dungeon + code:ZZXUAGPZ+GINUGGXA+NLNUIKUL + cheat + description:Unused level - Underground 2 + code:LZXUAGPZ+ZGNUGGXA+KLNUIKUL + cheat + description:Unused level - Sky 1 + code:GZXUAGPZ+SGNUGGXE+SZNUIKUU + cheat + description:Unused level - Sky 3 (level cannot be completed) + code:GZXUAGPZ+KGNUGGXA+ELNUIKUL + cheat + description:Unused level - Cloudy 1 + code:IZXUAGPX+OZNUGGXE+KZNUIKUU + cheat + description:Unused level - Pipe level + code:AZXUAGPX+APNUGGXE+NZNUIKUU + cheat + description:Unused level - Hilly level + code:LZXUAGPZ+SINUGGXE+ELNUIKUL + cheat + description:Unused level - Ice/Water + code:GZXUAGPX+XLNUGGXE+NLNUIKUL + cheat + description:Unused level - Cloudy (level cannot be completed) + code:IZXUAGPX+UZNUGGXE+SZNUIKUU + cheat + description:P meter always full + code:03DD:7F + cheat + description:Invincibility as Super Mario (alt) + code:00ED:01 + cheat + description:Invincibility as Fire Mario (alt) + code:00ED:02 + cheat + description:Invincibility as Raccoon Mario (alt) + code:00ED:03 + cheat + description:Invincibility as Frog Mario (alt) + code:00ED:04 + cheat + description:Invincibility as Tanooki + code:00ED:05 + cheat + description:Invincibility as Sledgehammer Mario (alt) + code:00ED:06 + +cartridge sha256:fe019a7da7fb7ecd2e6478bde546e6c5d6bba185d53e5c8692522ed8fdd617a2 + title:Super Pitfall (USA) + cheat + description:Infinite bullets + code:AEOYILPA + cheat + description:Infinite lives - 1P game + code:SZKSASVK + cheat + description:Infinite lives - P1 + code:SXESTSVK + cheat + description:Infinite lives - P2 + code:SXXSZSVK + cheat + description:30 bullets gained on pick-up + code:LENLELZA + cheat + description:10 bullets gained on pick-up + code:PENLELZA + cheat + description:Start with 1 life - both players + code:PAVIPALA + cheat + description:Start with 6 lives - both players + code:TAVIPALA + cheat + description:Start with 9 lives - both players + code:PAVIPALE + cheat + description:Start with 30 bullets + code:LEXKNYZA + cheat + description:Start with 10 bullets + code:PEXKNYZA + cheat + description:Invincibility (blinking) - both players + code:00DC:FF + +cartridge sha256:7c14c7e39943e7247c92d907f3362eab09a7306fb606d4a899a918fc6afd356a + title:Super Shinobi, The (unl) + cheat + description:Infinite health + code:04F5:09 + cheat + description:Infinite magic + code:010D:09 + cheat + description:Infinite Shurikens + code:0109:09+010B:09 + cheat + description:Always have powered-up Shurikens + code:00AF:01 + +cartridge sha256:d1defc7a6c6f96f89386c79ac887aa41a72fefa93ba22a8a08159ac891f73613 + title:Super Sprint (USA) (Unl) + cheat + description:Infinite continues + code:SZETVUVK + cheat + description:6 continues + code:YASSPALA + cheat + description:No continues + code:PASSPALA + cheat + description:More obstacles on tracks + code:IEKKNTAA+GXSGUVSE + cheat + description:Even more obstacles on tracks + code:ZEKKNTAE+GXSGUVSE + cheat + description:Lots and lots of obstacles on tracks + code:YEKKNTAE+GXSGUVSE + +cartridge sha256:7806ee6afcdf88ef6364da23af8b28f359ef7d850fe55224e188b8a01d5ade67 + title:Super Spy Hunter (USA) + cheat + description:Infinite health + code:SXVPEZSA + cheat + description:Start with max health gauge + code:GEXUOIGE + cheat + description:Infinite lives + code:0074:05 + cheat + description:Infinite health (alt) + code:007B:40 + +cartridge sha256:9ffc36dfc772e1020a9648949aecebab687d6b386d6f02526916d1d49973a78a + title:Superman (USA) + cheat + description:Never die when out of super power + code:AAXSEIEA + cheat + description:Never lose super power + code:SXNSSKSE + cheat + description:Start with lots of super power + code:XVUVYZIA + cheat + description:Double max power of all items at start + code:AVEOUIAL + cheat + description:Double usual item power on item power crystal pick-up + code:AXUPYLAP + cheat + description:Full item power on item power crystal pick-up + code:EXUPYLAP + cheat + description:Start at mission 2 + code:EZVPKSOZ+PAVPSIAA+KANPXSSE + cheat + description:Start at mission 3 + code:EZVPKSOZ+ZAVPSIAA+KANPXSSE + cheat + description:Start at mission 4 + code:EZVPKSOZ+LAVPSIAA+KANPXSSE + cheat + description:Start at mission 5 + code:EZVPKSOZ+GAVPSIAA+KANPXSSE + +cartridge sha256:d138aba5eb5c8cf1218abc7b57ad10709041fd68b6a6c47dd30432f8b33470e9 + title:Swamp Thing (USA) + cheat + description:Invincibility + code:PEVOTKPX+ESVOZGEY + cheat + description:Infinite health + code:SZNVZVVK + cheat + description:Infinite lives + code:SZNTIKVK + +cartridge sha256:553d6db3959c8ae3e3cfa598a33c57756b06653ce434fddd0de92bafb460cb05 + title:Sword Master (USA) + cheat + description:Invincibility + code:ALKZVZAP + cheat + description:Infinite health + code:SXSKNXSE+SZSGNXSE + cheat + description:Infinite continues + code:SZNTVUSE + cheat + description:Gain a level for every EXP point gained + code:AAEGKGPZ + cheat + description:Invincibility (alt) + code:042E:8F + cheat + description:Infinite health (alt) + code:042EF:0F + +cartridge sha256:cdd148ebf43ed8918b4cd5d03e685fe0f38b434a59ffb38f0d9ceb2ee7ca9d89 + title:Swords and Serpents (USA) + cheat + description:All characters have Scale Armor + code:VANGKTVE + cheat + description:Warriors start with a Great Sword + code:UEEKSTOE + cheat + description:Warriors start with a Great Axe + code:KEEKSTOE + cheat + description:Magicians start with a Wizard's Wand + code:SEEGETSE + cheat + description:Magicians start with more spells + code:YPKGSTLE + cheat + description:Magicians have greater spells + code:LAKKXTAA + cheat + description:Spells use up no magic points + code:GZKYLGOY + cheat + description:Thieves start with a Long Sword + code:XEOGVTXE + cheat + description:Thieves start with an Axe + code:KEOGVTXA + cheat + description:Start with 30 health points each + code:TPXGNVZE+TPXKSVZE + cheat + description:Start with 50 health points each + code:ZLXGNVZA+ZLXKSVZA + +cartridge sha256:f3955370fe7ecc99afc27cdccf3482f75f06e0f431e42823c95982bb553ad6b9 + title:Town & Country Surf Designs - Wood & Water Rage (USA) + cheat + description:Infinite lives for skating + code:GXUZZZVG + cheat + description:Infinite lives for surfing + code:GXNKALVG + cheat + description:When surfing lose only 1 symbol + code:PEOGILZA + cheat + description:When skating lose only 1 symbol if you fall into the ocean or a crack + code:PAEZYALA + cheat + description:Infinite time + code:GXKLXAVG + cheat + description:Increase time + code:LESPGZPA + cheat + description:Infinite lives + code:0047:04 + cheat + description:Infinite time (alt) + code:0037:09 + +cartridge sha256:cfa1cc0f40cf139b1ba61794838d52c029b40ea12194b4248178d8ae59c69b7a + title:Town & Country Surf Designs - Thrilla's Surfari (USA) + cheat + description:Infinite lives + code:OZSIZYVK + cheat + description:Can't collect Coconuts + code:OXEVIIVV + cheat + description:Start with 5 Coconuts plus what you've collected in sub-game + code:IAUALPAA + cheat + description:Start with 10 Coconuts plus what you've collected in sub-game + code:ZAUALPAE + cheat + description:Start with 15 Coconuts plus what you've collected in sub-game + code:YAUALPAE + cheat + description:Start with less health + code:PAXEIPZA + cheat + description:Start with a little more health + code:LAXEIPZA + cheat + description:Start with 2x health + code:GAXEIPZA + cheat + description:Start with a lot more health + code:PAXEIPZE + cheat + description:Start with 1 life + code:PAXEPPLA + cheat + description:Start with 5 lives + code:IAXEPPLA + cheat + description:Start with 7 lives + code:YAXEPPLA + cheat + description:Start with 9 lives + code:PAXEPPLE + cheat + description:Start with mega lives + code:OPXEPPLE + cheat + description:Start on level 1-3 (can't advance to next level) + code:ZENUATIA+GENUZTKL + cheat + description:Start on level 1-4 (can't advance to next level) + code:LENUATIA+GENUZTKL + cheat + description:Watch the level 2 Cinema (can't advance to next level) + code:GENUATIA+GENUZTKL + cheat + description:Start on level 2-2 (can't advance to next level) + code:TENUATIA+GENUZTKL + cheat + description:Start on level 2-3 (can't advance to next level) + code:YENUATIA+GENUZTKL + cheat + description:Start on level 2-4 (can't advance to next level) + code:AENUATIE+GENUZTKL + cheat + description:Have all 8 health slots + code:0006:08 + +cartridge sha256:b002d1ebee16a5fd2bcae480df8ccc7b8dc7a6f96a80f5fac8b76e078e4f42f0 + title:Tag Team Wrestling (USA) + cheat + description:Infinite health (glitchy) + code:OOUSLZSO + cheat + description:Never give up + code:SUNKXTVI + cheat + description:Infinite health - P1 + code:0048:18 + cheat + description:Infinite health - P2 + code:0058:18 + cheat + description:Infinite health - tag team partner + code:005D:18 + +cartridge sha256:65d11519c8bc1435a994e4f71362dbc734ca808ac3048b66e87c5a80475e3f5e + title:Takahashi Meijin no Bouken-jima IV (Japan) + cheat + description:Invincibility + code:EIEXYZEY + cheat + description:Infinite health + code:SXKGYZSA + +cartridge sha256:6d10e95fcbf4cd1179293106d526373ea43a0c2b8531e694288b147310d617c6 + title:TaleSpin (USA) + cheat + description:Infinite health + code:AAXEGPTA + cheat + description:Infinite continues + code:SXNKXLVG + cheat + description:Infinite lives from getting trapped by obstacles + code:GZKGNKVK + cheat + description:Add $1,000,000 to end-of-level bonus + code:PYVGUAAY + cheat + description:1 life after continue + code:ANNGVLLY + cheat + description:7 lives after continue + code:TNNGVLLY + cheat + description:10 lives after continue + code:PNNGVLLN + cheat + description:1 continue + code:PYEGITLY + cheat + description:6 continues + code:TYEGITLY + cheat + description:9 continues + code:PYEGITLN + cheat + description:Start with 1 life + code:AYVKZYLY + cheat + description:Start with 7 lives + code:TYVKZYLY + cheat + description:Start with 10 lives + code:PYVKZYLN + cheat + description:Invincibility (blinking) + code:007C:5B + cheat + description:Infinite health (alt) + code:05B6:60 + cheat + description:Infinite lives (alt) + code:05DB:79 + +cartridge sha256:f6e88113b5f64cf7ffd915dd60b49e55d7015aaeb8b232c87e9855d4b9759cbd + title:Target Renegade (USA) + cheat + description:Don't take most damage + code:SXVZVTSA + cheat + description:Take half damage from bosses + code:TASPSPGP + cheat + description:Infinite time + code:SZEAOZVG + cheat + description:Set timer to 5:00 for all levels + code:SXEATXSU + cheat + description:Hearts replenish health to maximum + code:AEKESZZA + cheat + description:Set timer to 3:00 for all levels + code:SXEATXSU+NKEEAZEE + cheat + description:Start on level 2 + code:PAOOYZAA + cheat + description:Start on level 3 + code:ZAOOYZAA + cheat + description:Start on level 4 + code:LAOOYZAA + cheat + description:Start on level 5 + code:GAOOYZAA + cheat + description:Start on level 6 + code:IAOOYZAA + cheat + description:Start on level 7 + code:TAOOYZAA + cheat + description:Infinite health + code:00DA:40+00DB:40 + cheat + description:Infinite time (alt) + code:00EB:09 + +cartridge sha256:d088f4b91a03dd6a618245fffb492bcda127c7faa6d880596aa5e751fdac0181 + title:Tecmo Bowl (USA) (Rev A) + cheat + description:Instant touchdowns - P1 + code:AAVELPLA + cheat + description:Instant touchdowns - P2 + code:AAEEKILA + cheat + description:Always kick with max power - P1 + code:IVXOKLZA+OXXOUUPV + cheat + description:Only 2 downs allowed + code:ZAXAYIGA+ZAXOTPGA + cheat + description:6 downs allowed + code:TAXAYIGA+TAXOTPGA + cheat + description:Infinite time (minutes) + code:008B:09 + cheat + description:Infinite time (seconds) + code:008A:99 + cheat + description:CPU/P2 has 0 points + code:0048:00 + +cartridge sha256:d2b56b27912cfc03756c94df6667fdf923c8a3746fa37e4632eeb4134ef4c200 + title:Tecmo Bowl (USA) + cheat + description:Instant touchdowns - P1 + code:AAVELPLA + cheat + description:Instant touchdowns - P2 + code:AAEEKILA + cheat + description:Always kick with max power - P1 + code:IVXOKLZA+OXXOUUPV + cheat + description:Only 2 downs allowed + code:ZAXAYIGA+ZAXOTPGA + cheat + description:6 downs allowed + code:TAXAYIGA+TAXOTPGA + cheat + description:Infinite time (minutes) + code:008B:09 + cheat + description:Infinite time (seconds) + code:008A:99 + cheat + description:CPU/P2 has 0 points + code:0048:00 + +cartridge sha256:54d809b38573248ff73e104505a57f71f8b4356c8a7983a363c2ee242f878205 + title:Tecmo NBA Basketball (USA) + cheat + description:Infinite timeouts + code:SLVUPUVS + cheat + description:2-pt. shots worth 1, 3-pt. shots worth 2 + code:AEOLVPPA + cheat + description:2-pt. shots worth 3, 3-pt. shots worth 4 + code:ZEOLVPPA + cheat + description:2-pt. shots worth 4, 3-pt. shots worth 5 + code:LEOLVPPA + cheat + description:2-pt. shots worth 5, 3-pt. shots worth 6 + code:GEOLVPPA + cheat + description:2-pt. shots worth 6, 3-pt. shots worth 7 + code:IEOLVPPA + cheat + description:3-pt. shots worth 2 pts. + code:AVNUVOVT + cheat + description:5-second violations become 10-second violations + code:NYSENZYE + cheat + description:No 10-second violations + code:NYOPTNZE + cheat + description:Longer shot clock after getting ball on rebound + code:ASOLSEAO + cheat + description:Shorter shot clock after getting ball on rebound + code:AEOLSEAO + +cartridge sha256:cd5ad84e6bba35c19098c6f9783b568e4f1218582a12ec0513e5fafbdabb0303 + title:Tecmo Super Bowl (USA) + cheat + description:Infinite time (continuous play) + code:SXNXPZVG + cheat + description:Almost every player has their skill level at 100 + code:ZXTISS + cheat + description:10 minutes per quarter instead of 5 + code:APUXLZIA + cheat + description:20 minutes per quarter + code:AZUXLZIA + cheat + description:2 minutes per quarter + code:ZAUXLZIA + cheat + description:Touchdown scores 0 instead of 6 - P1 + code:AAOATTTA + cheat + description:Touchdown scores 0 - P2 or computer + code:AEOEVITA + cheat + description:Touchdown scores 3 - P1 + code:LAOATTTA + cheat + description:Touchdown scores 3 - P2 or computer + code:LEOEVITA + cheat + description:Touchdown scores 9 - P1 + code:PAOATTTE + cheat + description:Touchdown scores 9 - P2 or computer + code:PEOEVITE + cheat + description:Touchdown scores 12 - P1 + code:GAOATTTE + cheat + description:Touchdown scores 12 - P2 or computer + code:GEOEVITE + cheat + description:Extra-point kick scores 0 instead of 1 - P1 + code:AAEALYPA + cheat + description:Extra-point kick scores 0 - P2 or computer + code:AEEEUTPA + cheat + description:Extra-point kick scores 2 - P1 + code:ZAEALYPA + cheat + description:Extra-point kick scores 2 - P2 or computer + code:ZEEEUTPA + cheat + description:Extra-point kick scores 3 - P1 + code:LAEALYPA + cheat + description:Extra-point kick scores 3 - P2 or computer + code:LEEEUTPA + cheat + description:Extra-point kick scores 6 - P1 + code:TAEALYPA + cheat + description:Extra-point kick scores 6 - P2 or computer + code:TEEEUTPA + cheat + description:Field goal scores 0 instead of 3 - P1 + code:AEKAGGLA + cheat + description:Field goal scores 0 - P2 or computer + code:AAKEKGLA + cheat + description:Field goal scores 1 - P1 + code:PEKAGGLA + cheat + description:Field goal scores 1 - P2 or computer + code:PAKEKGLA + cheat + description:Field goal scores 6 - P1 + code:TEKAGGLA + cheat + description:Field goal scores 6 - P2 or computer + code:TAKEKGLA + cheat + description:Field goal scores 9 - P1 + code:PEKAGGLE + cheat + description:Field goal scores 9 - P2 or computer + code:PAKEKGLE + cheat + description:Safety scores 0 instead of 2 - P1 + code:AASASIZA + cheat + description:Safety scores 0 - P2 or computer + code:AEKEIIZA + cheat + description:Safety scores 1 - P1 + code:PASASIZA + cheat + description:Safety scores 1 - P2 or computer + code:PEKEIIZA + cheat + description:Safety scores 4 - P1 + code:GASASIZA + cheat + description:Safety scores 4 - P2 or computer + code:GEKEIIZA + cheat + description:Safety scores 6 - P1 + code:TASASIZA + cheat + description:Safety scores 6 - P2 or computer + code:TEKEIIZA + +cartridge sha256:b6adca3680ba28efd41b2216cfcb9af66ed175e4359f0fbd5eda90e6cb6380e8 + title:Tecmo World Cup Soccer (Europe) + cheat + description:Never lose guts + code:OXUEPTOO + cheat + description:Everyone has more guts + code:ASNIEIAZ+TENIOILA + +cartridge sha256:daf07341c80a866333d69c7560f8402123adbb345b15185480393f0db6822b16 + title:Tecmo World Wrestling (USA) + cheat + description:Infinite health - P1 + code:SXKIIYSA + cheat + description:Half training time allowed + code:IEUSTOZA + cheat + description:Double training time allowed + code:GOUSTOZA + cheat + description:Lose all energy after being on the receiving end of a move + code:OOPSYY + +cartridge sha256:892468d05a1097769d14e0ed4822267760d85dbfc79d83a0235878109f839dd1 + title:Teenage Mutant Ninja Turtles (USA) + cheat + description:Invincibility + code:SXOPPIAX + cheat + description:Infinite health + code:AOSOUAST + cheat + description:Infinite health (alt) + code:OUVPUEOO + cheat + description:Infinite health (alt 2) + code:GXSOUAST + cheat + description:10 weapons on pick-up + code:ZENOATGO + cheat + description:50 weapons on pick-up + code:ZUNOATGP + cheat + description:99 weapons on pick-up + code:LVNOATGP + cheat + description:20 missiles on pick-up + code:GPUOLNZA + cheat + description:99 missiles on pick-up + code:YTUOLNZA + cheat + description:Don't take damage from non-killing seaweed + code:SXVZGSOO + cheat + description:Full health boost from pizza slices + code:AEOOGTZA + cheat + description:Double rope on pick-up + code:TAKOPYLA + cheat + description:Never lose rope + code:SXVXTLVG + cheat + description:Reduce recovery time + code:SXOZTVSE + cheat + description:No sound + code:IIIPAP + cheat + description:Start a new game to view the ending + code:IAXGPTZA + cheat + description:Invincibility (alt) + code:0500:15 + cheat + description:Infinite health - Leonardo + code:0077:80 + cheat + description:Infinite health - Raphael + code:0078:80 + cheat + description:Infinite health - Michaelangelo + code:0079:80 + cheat + description:Infinite health - Donatello + code:007A:80 + cheat + description:Infinite Ropes + code:00A7:09 + cheat + description:Infinite Missiles + code:00BF:63 + cheat + description:Infinite time on water level + code:00BB:32 + cheat + description:Have Scrolls - Leonardo + code:0073:04 + cheat + description:Have Scrolls - Raphael + code:0074:04 + cheat + description:Have Scrolls - Michaelangelo + code:0075:04 + cheat + description:Have Scrolls - Donatello + code:0076:04 + cheat + description:99 weapons - Leonardo + code:00A8:63 + cheat + description:99 weapons - Raphael + code:00A9:63 + cheat + description:99 weapons - Michaelangelo + code:00AA:63 + cheat + description:99 weapons - Donatello + code:00AB:63 + cheat + description:Permanent rolling power-up (disable on water level) + code:0540:91 + +cartridge sha256:368d7ea3a066d4dc937473ca6cfc3e0d79d928b2308fff5ddd6ff199c7da153d + title:Teenage Mutant Ninja Turtles II - The Arcade Game (USA) + cheat + description:Invincibility (except grabs from behind) - both players + code:ESUEPZEY + cheat + description:Infinite health - both players + code:SUVASVSO+SLETOKSO + cheat + description:Infinite lives - both players + code:AAEAULPA + cheat + description:One hit kills - both players + code:AOXVXZEI + cheat + description:Stronger turtle weapon + code:PEXTKZZE + cheat + description:Stronger jump + attack + code:PEOVKZGE + cheat + description:Stronger jump + attack + code:ZEOVKZGA + cheat + description:Stronger kick + code:PEXTEZLE + cheat + description:Weaker kick + code:PEXTEZLA + cheat + description:In two-turtle mode, when one player is revived the other player's spare life won't get used + code:SXEAPZVG+SZUAYZVG + cheat + description:Enable stage select and 10 lives code + code:OEVKNZAA + cheat + description:Press Start to finish the level + code:GESSGLPA+GUSSTUIU + cheat + description:Start with 1 life + code:PEOIAPZA + cheat + description:Start with 6 lives + code:TEOIAPZA + cheat + description:Start with 9 lives + code:PEOIAPZE + cheat + description:Invincibility - P1 + code:0093:2B + cheat + description:Invincibility - P2 + code:0094:2B + cheat + description:Infinite health - P1 + code:0568:37 + cheat + description:Infinite health - P2 + code:056A:37 + cheat + description:Infinite lives - P1 + code:004D:09 + cheat + description:Infinite lives - P2 + code:004E:09 + cheat + description:Infinite continues + code:03D3:03 + cheat + description:One hit kills - both players (alt) + code:EAAA:10 + cheat + description:Enable stage select after choosing your turtle + code:0025:81 + +cartridge sha256:9f671090ffd2bb1dc95b9d413c3627f7aa0d576435eeb5b868fa7ca9c29c1190 + title:Teenage Mutant Ninja Turtles III - The Manhattan Project (USA) + cheat + description:Invincibility (except grabs from behind) + code:ENSKKIEI + cheat + description:Infinite health + code:SLXUTXVS+SLKXPKSO + cheat + description:Infinite lives + code:AENKLZPA + cheat + description:Infinite continues + code:SXNSKKVK + cheat + description:No health loss from using turbo attack + code:AAESYXAA + cheat + description:Hit anywhere - both players + code:AAEZVETP+AANXNZNI+AAOZEAGP+APXZXEUX+XTXZEEOS+XTXZOEAN + cheat + description:High-jump + code:ALUGVYAG + cheat + description:Super-jump + code:AZUGVYAK + cheat + description:Mega-jump + code:AZUGVYAG + cheat + description:1 continue + code:PAUZOGLA + cheat + description:9 continues + code:PAUZOGLE + cheat + description:Start with 1 life instead of 4 + code:AEOAALLA + cheat + description:Start with 6 lives + code:IEOAALLA + cheat + description:Start with 9 lives + code:AEOAALLE + cheat + description:Infinite health - P1 + code:04F1:7F + cheat + description:Infinite health - P2 + code:04F2:7F + cheat + description:Infinite lives - P1 + code:006A:05 + cheat + description:Infinite lives - P2 + code:006B:05 + cheat + description:Infinite continues + code:07B0:05 + cheat + description:Enemies automatically die + code:0626:00+0627:00+0628:00 + cheat + description:Start on scene 02 - Ocean + code:0058:01 + cheat + description:Start on scene 03 - Battleship + code:0058:02 + cheat + description:Start on scene 04 - Bridge + code:0058:03 + cheat + description:Start on scene 05 - N.Y. + code:0058:04 + cheat + description:Start on scene 06 - Platform + code:0058:05 + cheat + description:Start on scene 07 - Sewer + code:0058:06 + cheat + description:Start on scene 08 - Sewer 2 + code:0058:07 + cheat + description:Start on scene 09 - Technodrome + code:0058:08 + cheat + description:Start on scene 10 - Technodrome 2 + code:0058:09 + cheat + description:Start on scene 11 - Building + code:0058:0A + cheat + description:Start on scene 12 - Roof + code:0058:0B + cheat + description:Start on scene 13 - Spaceship + code:0058:0C + cheat + description:Start on scene 14 - Spaceship 2 + code:0058:0D + cheat + description:Start on scene 15 - Spaceship 3 + code:0058:0E + +cartridge sha256:10e2091a1c5e3ff3f636944fb274cd61db09dc25d0c14868710675cf1f86fd0b + title:Teenage Mutant Ninja Turtles - Tournament Fighters (USA) + cheat + description:Infinite health + code:OZVVVTEO+ELVVNVLP+SANTOVSU + cheat + description:Infinite time + code:GXKVKXVK + cheat + description:Select ultra strength (ignore strength meter and keep pushing to the right) - both players + code:NYUEESPYE + cheat + description:Select any character in story mode + code:YAVAZLGA + cheat + description:Infinite continues + code:OKKEZTVG + cheat + description:First hit wins round + code:PEXAGAEL + cheat + description:One round wins match + code:OZNEOXPV+ZANEXZPA + cheat + description:Start with 1/3 health - both players + code:AUXAGAEL + cheat + description:Start a new game to view the ending + code:LEXYLGZE + cheat + description:Infinite health - P1 + code:0590:B0 + cheat + description:No health - P2 / CPU + code:0591:00 + cheat + description:Infinite time (one's digit) + code:0673:09 + cheat + description:Infinite time (ten's digit) + code:0672:09 + cheat + description:Turn off CPU's jumping, blocking and fighting routine + code:06C3:00+06C7:00+06C9:00+06CB:00 + +cartridge sha256:dd89b8e08738243d20740194ef814b011df138d820844ee4e53d3a6e536b1c83 + title:Terminator, The (USA, Europe) + cheat + description:Infinite health + code:SXNLNESE + cheat + description:Infinite Grenades + code:SXVYIEVK + +cartridge sha256:6f66d14e5f17ca244444e74538afe31f8abda8376b5b0205afaeb86075407c45 + title:Terminator 2 - Judgment Day (USA) + cheat + description:Infinite health + code:GXVTXZAX + cheat + description:Take minimal damage + code:OXNVKXPK+VNNVSXNN + cheat + description:Infinite lives + code:SXOATOVK + cheat + description:Super-jump + code:XNVOSOKN + cheat + description:Slower running + code:PAOOVZZA+PAUOXZZA + cheat + description:Faster running + code:LAOOVZZA+LAUOXZZA + cheat + description:Faster and longer jumping + code:LESPKGZA+LEVPEGZA + cheat + description:Start with 1 life + code:PANXPLGA + cheat + description:Start with 9 lives + code:PANXPLGE + +cartridge sha256:667bcf3ca1ebcf6f71fccd412ced546f4aba3b8cd2fc30d173cf6d3b4c15846a + title:Terra Cresta (USA) + cheat + description:Invincibility + code:KTKSLGAZ + cheat + description:Infinite lives + code:SZKVPTVG + cheat + description:Infinite "ship formation" splits + code:SXSTULVG + cheat + description:9 "ship formation" splits + code:PEOTEALE+PEKGETLE + cheat + description:A secret mega-weapon + code:AEVKNYLA + cheat + description:Start with 1 life + code:AAKSPGZA + cheat + description:Start with 6 lives + code:IAKSPGZA + cheat + description:Start with 9 lives + code:AAKSPGZE + +cartridge sha256:2ae5fb18a1bf841077e3872ba05060f030ea0bfc573994b2f8fe2fb570dc7853 + title:Tetris (USA) + cheat + description:Disable Game Over (press start) + code:GAOPEILA+GGOPSZEN+XPOPNZSX+YGOPVZAL + cheat + description:999999 score with one piece dropped + code:AEEOUKAA + cheat + description:Puzzle area doesn't disappear on pause + code:TOUZYLTO + cheat + description:2P interactive game + code:ENEALYNN + cheat + description:Need only complete 10 lines in game B + code:APSEGYIZ + cheat + description:Faster forced fall rate + code:PASAUPPE + cheat + description:Must complete 50 lines in game B + code:AISEGYIZ + cheat + description:Must complete 80 lines in game B + code:EASEGYIZ + +cartridge sha256:9daa4bec3013ae7ef498318432f438d70374af294d1dce28edd3c466aaf6b740 + title:Tetris (USA) (Unl) + cheat + description:Always get straight pieces + code:OZKPEPEN+PAKPOOOY + cheat + description:Speed stays the same + code:OZXPKLGX+PZXPSUYZ + cheat + description:Press down to stop blocks from falling + code:GAAEPP + cheat + description:Press down to rotate block very fast + code:PPAEPO + +cartridge sha256:dd77dc88d380807990f55d0b1b55c151f78c480a0a0895e91d6edfb945ad71d7 + title:Tetris 2 (USA) + cheat + description:(1P game) Speed doesn't increase + code:AAUEUSSO + cheat + description:(1P game) Speed increases much faster + code:VNUEUSSO + cheat + description:(1P game) Start and stay at speed of 25 + code:TEXAKYPA + cheat + description:(1P game) Max speed is 2 + code:ZEKESSPP+PESAOSAP + cheat + description:(1P game) Max speed is 10 + code:ZEKESSPO+PESAOSAO + cheat + description:(1P game) Max speed is 15 + code:YEKESSPO+TESAOSAO + cheat + description:(1P game) Max speed is 20 + code:GOKESSPP+LOSAOSAP + cheat + description:(1P vs 2P or 1P vs Com) Every round starts with 4 fixed blocks + code:OZNETPOU+PANEYPAA + cheat + description:(1P vs 2P or 1P vs Com) Every round starts with 10 fixed blocks + code:OZNETPOU+YANEYPAA + cheat + description:(1P vs 2P or 1P vs Com) Every round starts with 15 fixed blocks + code:OZNETPOU+GANEYPAE + cheat + description:(1P vs 2P or 1P vs Com) Every round starts with 20 fixed blocks + code:OZNETPOU+PPNEYPAA + cheat + description:(All game types) Cannot pause game + code:AAVZVYEA + cheat + description:(All game types) Don't hide remaining pieces during pause + code:AVEXOYXZ + +cartridge sha256:18d41a2dc65d8afce295eaf29c391539a69d7cfe6dd32503713ae13d4495a545 + title:Thexder (Japan) + cheat + description:Infinite health + code:SXEPSISA + cheat + description:Infinite shield + code:SZEOKAVG + cheat + description:Start on last level + code:0074:63 + +cartridge sha256:e3be0290f198fceed633b037d9201aa4b95460617551b3a9fb5bb212b153a2d4 + title:Thunder & Lightning (USA) + cheat + description:Infinite lives - P1 + code:SINPPLVI + +cartridge sha256:c0c3d7c2682dd2e0dd2122682e2ae3a9ee7aa3d095bd22a36c759c29b5d05615 + title:Thunderbirds (USA) + cheat + description:Don't lose life points when colliding with enemy + code:SXNTOVVK + cheat + description:Don't lose life points when hit + code:SZUVUNVK + cheat + description:Don't lose energy points when colliding with enemy + code:SXNVVVVK + cheat + description:Don't lose energy points when hit + code:SZKVENVK + cheat + description:81 Days to defeat Hood + code:PSEKIVGL + cheat + description:30 Days to defeat Hood + code:TOEKIVGU + cheat + description:Limited forward movement + code:ATXEANAA+ATXEGNAA + cheat + description:Faster craft + code:GEXETTZA+GEXEZTZA + cheat + description:Full firepower on first pick-up + code:EZUAETEG+XTUAKVEK + +cartridge sha256:c56af43761cb601a068cdc88c2fc36f715921dbae9a8a9d8c10479146c47ccb9 + title:Thundercade (USA) + cheat + description:Infinite lives + code:GXVYPZVI + cheat + description:Infinite Missiles + code:AAUNLIPP + cheat + description:Infinite Bombs + code:GZXYZTVI + cheat + description:Autofire + code:ZANYGSZA + cheat + description:Start with double Bombs + code:TENNPZLA + cheat + description:Start with triple Bombs + code:PENNPZLE + cheat + description:Start with 1 life + code:PAOYIILA + cheat + description:Start with 6 lives + code:TAOYIILA + cheat + description:Start with 9 lives + code:PAOYIILE + +cartridge sha256:e115dbf3de0a4e674ff3f9081d7f97b89f636d81ce524119c0af4ef799490695 + title:Thunder Warrior (Asia) (Unl) + cheat + description:Invincibility + code:ESUUTLEY+ESKLLLEY + cheat + description:Infinite health + code:SXXPGUVK + cheat + description:Infinite magic + code:SXKAEOVK + cheat + description:Infinite lives + code:SZNEIEVK + cheat + description:Keep weapon after losing a life + code:AVSPOUSA + cheat + description:Start with 9 lives + code:PAUXAGLE + +cartridge sha256:403fe1c4454dc1e23fb272c88f70ba30dd5e860ab48ecff59420a09fc84e9a2d + title:Tiger-Heli (USA) + cheat + description:Invincibility + code:SZSYAEGK + cheat + description:Infinite lives - 1P game + code:SLXLGNVS + cheat + description:Infinite lives - both players + code:SUKLINVS+SUVULNVS + cheat + description:Autofire capability + code:TEKNAXIA + cheat + description:Burstfire capability + code:ZEKNAXIA + cheat + description:Turbo boost + code:GXVNZLZP + cheat + description:Extra life every 5 bonus blocks + code:LASNVVZA + cheat + description:Start with 2 lives - 1P game + code:AEUUYTZA + cheat + description:Start with 9 lives - 1P game + code:AEUUYTZE + cheat + description:Start with 6 lives - P1 in a 2P game + code:IASUYYZA + cheat + description:Start with 9 lives - P1 in a 2P game + code:AASUYYZE + cheat + description:Start with 6 lives - P2 + code:IANLZYZA + cheat + description:Start with 9 lives - P2 + code:AANLZYZE + cheat + description:Start with 2 little-helis after dying + code:XTVLUEZK + +cartridge sha256:13353e4e94633eba066e024ea7050b0801a8ccbe4c03bd97656852df4d2f3359 + title:Time Lord (USA) + cheat + description:Infinite health + code:SZVSLOSE + cheat + description:Infinite lives + code:SZUKSKVK + cheat + description:Moonwalking (don't combine with super speed) + code:AAXKXTPA+PAUGVTAA + cheat + description:Super speed (don't combine with moonwalking) + code:PESKOTAA+PEOGSTAA + cheat + description:Start with 1 life + code:PEEKYPLA + cheat + description:Start with 6 lives + code:TEEKYPLA + cheat + description:Start with 9 lives + code:PEEKYPLE + +cartridge sha256:c47a01c9b32642ad3145316804e64b0475a20863e42e81d17c664d03dcdde3c5 + title:Tiny Toon Adventures (USA) + cheat + description:Invincibility + code:EYKEGPEI + cheat + description:Infinite health after collecting one heart + code:SZOOSVVK + cheat + description:Infinite health and one Carrot + code:SEOEYXKX + cheat + description:Infinite time + code:SIKINXVS + cheat + description:Infinite lives + code:SZNOUNVK + cheat + description:Slow down timer + code:YYXIXXLU + cheat + description:Speed up timer + code:YPXIXXLU + cheat + description:Multi-jump + code:AASPPVPZ + cheat + description:Pick-up more hearts + code:AEEPPYPA + cheat + description:Power decreases slower when using Dizzy Devil's spin attack + code:PEVOIPZA + cheat + description:Press Start to finish the level (don't use on 6-3) + code:GENIVPPE+GKNSEOIK + cheat + description:Start a new game to view the ending + code:AOOKSYAA + cheat + description:1 life after continue + code:AEXZNZZA + cheat + description:6 lives after continue + code:IEXZNZZA + cheat + description:9 lives after continue + code:AEXZNZZE + cheat + description:Start with 1 life + code:AAXKUYZA + cheat + description:Start with 6 lives + code:IAXKUYZA + cheat + description:Start with 9 lives + code:AAXKUYZE + cheat + description:Start on level 2 + code:VASGOYSA+XZXKNNOZ+IAUGEYPA + cheat + description:Start on level 3 + code:VASGOYSA+XZXKNNOZ+ZAUGEYPE + cheat + description:Start on level 4 + code:VASGOYSA+XZXKNNOZ+YAUGEYPE + cheat + description:Start on level 5 + code:VASGOYSA+XZXKNNOZ+GPUGEYPA + +cartridge sha256:d4a94fd07859485fc2aac73d627933b70e1977c93b744ec3d71b66d4365ab7f7 + title:Tiny Toon Adventures 2 - Trouble in Wackyland (USA) + cheat + description:Invincibility + code:SAOAZASZ+EIOAGAEY + cheat + description:Infinite time + code:SZUYAZAX + cheat + description:Protection against hits on log ride + code:SXUXVXVK + cheat + description:Protection against hits on train + code:SZSEASVK + cheat + description:Protection against hits on bumper cars + code:SZOOUXVK + cheat + description:Protection against hits on roller coaster + code:SXKAYUVK + cheat + description:Protection against hits in fun house + code:SZSALOVK + cheat + description:Log ride costs nothing instead of 3 tickets + code:AANPYPLA + cheat + description:Log ride costs 5 tickets + code:IANPYPLA + cheat + description:Train costs nothing instead of 2 tickets + code:AANPIPZA + cheat + description:Train costs 5 tickets + code:IANPIPZA + cheat + description:Roller coaster costs nothing instead of 4 tickets + code:AANPPPGA + cheat + description:Roller coaster costs 6 tickets + code:TANPPPGA + cheat + description:Bumper cars cost nothing instead of 1 ticket + code:AANPLPPA + cheat + description:Bumper cars cost 4 tickets + code:GANPLPPA + cheat + description:Fun house costs nothing instead of 50 normal tickets + code:AANOZPIA + cheat + description:Fun house costs 10 normal tickets + code:PANOZPIA + cheat + description:Fun house costs 90 normal tickets + code:PANOZPIE + cheat + description:Start a new game to view the ending + code:PAKYINAE + cheat + description:Start with 20 tickets instead of 10 + code:ZAEYPYPA + cheat + description:Start with 50 tickets instead of 10 + code:IAEYPYPA + cheat + description:Start with 90 tickets instead of 10 + code:PAEYPYPE + cheat + description:Start with 110 tickets instead of 10 + code:VVVNAVSE + +cartridge sha256:f80e57788e32f73852d7d2aa4831edfe4c4bd5b8a02a322995263a13597c2f0c + title:Titan Warriors (USA) (Proto) + cheat + description:Invincibility against enemies + code:SZSNSGSA + cheat + description:Infinite lives + code:SZSPLKVK + +cartridge sha256:44569cef71a0b859bd0390e0155b19077ddef4a684f6fba6569a5f918910d4a2 + title:To the Earth (USA) + cheat + description:Shots use up no energy + code:AAEUXTGA + cheat + description:Shots use up less energy + code:ZAEUXTGA + cheat + description:Shots use up more energy + code:AAEUXTGE + cheat + description:Enemy bombs do no damage + code:AEUVEYGP + cheat + description:Enemy bombs do half damage + code:AEUVEYGO + cheat + description:Enemy bombs do more damage + code:AXUVEYGO + cheat + description:Bonus energy for shooting enemy + code:GOEUEVZA + cheat + description:Less energy for shooting enemy + code:GEEUEVZA + cheat + description:No energy for shooting enemy + code:AEEUEVZA + +cartridge sha256:e580f51b06217b102e56ec98fff7c4ebad5b925fa3a28042d67433cffa8c5cdc + title:Toki (USA) + cheat + description:Infinite health + code:EESEYEVG + cheat + description:Infinite weapons + code:SZNOGUVV+SXEOLUVV+SXOOZUSE + cheat + description:Infinite time + code:AAKEVYPA + cheat + description:Infinite lives + code:SXNYZSVK + cheat + description:Hit anywhere - normal enemies + code:SXSETVSO+XVEAPTAV + cheat + description:When weapon runs out of ammo it's replaced with the double weapon + code:PEOPTLAA + cheat + description:When weapon runs out of ammo it's replaced with the wave weapon + code:ZEOPTLAA + cheat + description:When weapon runs out of ammo it's replaced with the 3-way weapon + code:LEOPTLAA + cheat + description:When weapon runs out of ammo it's replaced with the flame weapon + code:GEOPTLAA + cheat + description:When weapon runs out of ammo it's replaced with the fireball weapon + code:IEOPTLAA + cheat + description:Start with less time + code:PAEIKALA+PAKAGALA + cheat + description:Start with more time + code:IAEIKALA+IAKAGALA + cheat + description:Start with even more time + code:PAEIKALE+PAKAGALE + cheat + description:Start with one heart - first life only + code:PAENPIZA + cheat + description:Start with one heart - after first life + code:AENYTIZA + cheat + description:Start with 1 life + code:AEKYXYZA + cheat + description:Start with 2 lives + code:PEKYXYZA + cheat + description:Start with 5 lives + code:GEKYXYZA + cheat + description:Start with 9 lives + code:AEKYXYZE + cheat + description:Infinite health - P1 + code:011C:02 + cheat + description:Infinite time (hundred's digit) + code:0576:09 + cheat + description:Infinite time (ten's digit) + code:0577:09 + cheat + description:Infinite time (one's digit) + code:0578:09 + cheat + description:Infinite lives - P1 + code:0114:09 + cheat + description:Infinite Coins (ten's digit) + code:0118:09 + cheat + description:Infinite Coins (one's digit) + code:0119:09 + cheat + description:Start on stage 2 - Lake Neptune + code:0116:01 + cheat + description:Start on stage 3 - Cavern Of Fire + code:0116:02 + cheat + description:Start on stage 4 - Ice Palace + code:0116:03 + cheat + description:Start on stage 5 - Dark Jungle + code:0116:04 + cheat + description:Start on stage 6 - Golden Palace + code:0116:05 + +cartridge sha256:b49e3b3c2a307e9c24715ea5863d6c80b805f9566eb1f468a4c701cf54605a5a + title:Tom & Jerry - The Ultimate Game of Cat and Mouse! (USA) + cheat + description:Infinite health + code:AEXYPAPA + cheat + description:Infinite lives + code:SXSNYEVK + cheat + description:Minimum health (one touch kills) + code:LEXYPAPA + cheat + description:Start with 1 life + code:PASNVZLA + cheat + description:Start with 6 lives + code:TASNVZLA + cheat + description:Start with 9 lives + code:PASNVZLE + cheat + description:Start on world 2 + code:AEVYKPAE + cheat + description:Start on world 3 + code:AOVYKPAA + cheat + description:Start on world 4 + code:AOVYKPAE + cheat + description:Start on world 5 + code:AXVYKPAA + +cartridge sha256:fe052f7f6b4b41dcbc009860e0c997c31e2e236eb46d713137ee773cce96105e + title:Toobin' (USA) (Unl) + cheat + description:Infinite lives + code:SXUTGIVG + cheat + description:Infinite cans + code:SZEZZIVG + cheat + description:Turbo left and right movement + code:ALKXTAAZ+ALVXLAAZ + cheat + description:Start with 2 lives + code:PAOTZTLA + cheat + description:Start with 6 lives + code:TAOTZTLA + cheat + description:Start with 9 lives + code:PAOTZTLE + cheat + description:Start with 18 cans + code:ZPOTTTTA + cheat + description:Start with 12 cans + code:GAOTTTTE + cheat + description:Start with 1 can + code:PAOTTTTA + cheat + description:Start on level 2 + code:PAOZEAAA + cheat + description:Start on level 4 + code:LAOZEAAA + cheat + description:Start on level 6 + code:IAOZEAAA + cheat + description:Start on level 8 + code:YAOZEAAA + cheat + description:Invincibility (glitchy) + code:02D3:00 + cheat + description:Infinite patches + code:006E:09 + cheat + description:Infinite cans (alt) + code:004C:FF + cheat + description:Have all letters + code:006D:7F + cheat + description:Faster shots + code:003F:02 + cheat + description:Don't go into dying animation (use with invincibility) + code:004A:00+004B:00 + +cartridge sha256:e788ae1dff1b868795395e19357525b93ddd52ac86f6a505d14eac5fa323b023 + title:Top Gun (USA) (Rev A) + cheat + description:Immune to Bullets (not Missiles) + code:AEKSNLLA + cheat + description:Infinite fuel + code:GXUSNGVG + cheat + description:Infinite Missiles + code:GXKIKIVG + cheat + description:Take off with double Hound Missiles + code:ASEKTOAZ + cheat + description:Take off with double Wolf Missiles + code:AXEKYPGO + cheat + description:Take off with double Tiger Missiles + code:GOOGAOZA + cheat + description:Start with half fuel + code:IANKLOZA + cheat + description:Start on mission 2 + code:ZAEGLPPA + cheat + description:Start on mission 3 + code:LAEGLPPA + cheat + description:Start on mission 4 + code:GAEGLPPA + cheat + description:Infinite health + code:004E:0C + cheat + description:Infinite fuel (alt) + code:0036:0A + cheat + description:Infinite lives + code:0031:02 + cheat + description:Infinite Missiles + code:003C:3F + +cartridge sha256:aa43f3138d4f731e5e8df530dbf8fc1f6f45303b84589f7a0715e392887f3dff + title:Top Gun (USA) + cheat + description:Immune to Bullets (not Missiles) + code:AEKSNLLA + cheat + description:Infinite fuel + code:GXUSNGVG + cheat + description:Infinite Missiles + code:GXKIKIVG + cheat + description:Always land safely on Aircraft Carrier + code:AAXLIYGA+SZXLLTSA + cheat + description:Take off with double Hound Missiles + code:ASEKTOAZ + cheat + description:Take off with double Wolf Missiles + code:AXEKYPGO + cheat + description:Take off with double Tiger Missiles + code:GOOGAOZA + cheat + description:Start with half fuel + code:IANKLOZA + cheat + description:Start on mission 2 + code:ZAEGLPPA + cheat + description:Start on mission 3 + code:LAEGLPPA + cheat + description:Start on mission 4 + code:GAEGLPPA + cheat + description:Infinite health + code:004E:0C + cheat + description:Infinite fuel (alt) + code:0036:0A + cheat + description:Infinite lives + code:0031:02 + cheat + description:Infinite Missiles + code:003C:3F + +cartridge sha256:55375474cdebdb05eeec27494761b686a7df63b8f874516004f1739760665c87 + title:Top Gun - The Second Mission (USA) + cheat + description:Invincibility + code:ASEAVLEY + cheat + description:Infinite lives + code:SZVYLIVG + cheat + description:Infinite missiles - 1P game + code:AAKEUYPA + cheat + description:Infinite missiles - 2P game + code:AENAZIPA + cheat + description:60 Phoenix missiles - 1P game + code:KUVZTIKO + cheat + description:20 Phoenix missiles - 2P game + code:KOVXTISA + cheat + description:Start with 1 life + code:PASYALLA + cheat + description:Start with 6 lives + code:TASYALLA + cheat + description:Start with 9 lives + code:PASYALLE + +cartridge sha256:45067f85328eabb3b8cb2bceec72192bfa8d73494521660f171b9ed6d151fdea + title:Total Recall (USA) + cheat + description:Infinite health + code:AVNVOAKZ + cheat + description:Most enemies easier to kill + code:GXUIIXSO + cheat + description:Take less damage + code:PENVKEGE + cheat + description:Gain maximum health from canisters + code:XYUVNUXT + cheat + description:Start with less health + code:OZNKEPSX+ALNKOOLZ + cheat + description:Start with more health + code:OZNKEPSX+NYNKOOLX + cheat + description:Invincibility + code:007F:03 + cheat + description:Infinite health (alt) + code:02C0:FA + +cartridge sha256:0bd29c5b583570e195e05a4272e69b74257db1f4ff928d59c8eb1022bad871ce + title:Totally Rad (USA) + cheat + description:Infinite health + code:SVVNTKON + cheat + description:Infinite magic + code:GXXAPKSN + cheat + description:Immune to fire and water + code:SZVAYIVG + cheat + description:Infinite lives + code:SZSEYXVK + cheat + description:Super-jump + code:AOOAYGAO + cheat + description:Mega-jump + code:YOOAYGAO + cheat + description:Half a life or half magic give full health or magic + code:TEEONALA + cheat + description:Start with 1 life + code:AEUXSTZA + cheat + description:Start with 6 lives + code:IEUXSTZA + cheat + description:Start with 9 lives + code:AEUXSTZE + cheat + description:Infinite health (alt) + code:006E:0C + cheat + description:Infinite lives (alt) + code:05D4:63 + +cartridge sha256:5ec7c3e91bfd5800073286ee978b1d152c19f924837788eb72700c7c01261fa4 + title:Tower of Druaga, The (Japan) + cheat + description:Invincibility + code:OXNUATSX+OZELLGSX + cheat + description:Infinite lives + code:00CB:03 + cheat + description:Infinite time + code:00B7:69 + cheat + description:Doors are always open + code:0099:40 + cheat + description:Treasure instantly appears + code:00E5:01 + +cartridge sha256:c3fec0650f1709911432e8953a6075cb5883601a209323ba0744cb19d82b7f80 + title:Toxic Crusaders (USA) + cheat + description:Infinite lives + code:KXKLTIKA + cheat + description:Infinite health + code:SXXVYGSA + cheat + description:Never lose Mop + code:SXXTXNSE+PASLEAAA + cheat + description:Invincibility + code:020F:00 + cheat + description:Infinite health (alt) + code:00DE:08 + cheat + description:Infinite lives (alt) + code:00DD:09 + cheat + description:Never lose weapon + code:020B:01 + +cartridge sha256:a2812d80b3057aac9753f48247a7a46b29bea0b9aec04ca4c327180085c25b58 + title:Track & Field (USA) + cheat + description:Almost always qualify in Skeet Shooting and Archery + code:NTXKTNKT + cheat + description:You don't have to score any points to qualify for Skeet Shooting, Triple Jump and Archery + code:UKUKIGKG + +cartridge sha256:efb93dcae29f1ff85b58ccb9450c23d528073a019493d88a9abcabe4ca9aca4f + title:Transformers - Convoy no Nazo (Japan) + cheat + description:Invincibility + code:AIUKAZEY+AVXGPGSZ + cheat + description:Hit anywhere (enemies and platforms) + code:AEKGYZGZ+ASVKZZEP+SLEKLUSO + cheat + description:Moon jump + code:AAEOTOTZ+AAEPZOZL+AENOAAYZ + cheat + description:Solve level 9 maze using any path + code:AYNEAZEY + +cartridge sha256:58d2f6abe4445dadc332f37a34af54e78b6af47a8c0e6313ef898ef6db046f4f + title:Treasure Master (USA) + cheat + description:Invincibility + code:KVNPUXEL+LENPKZIA + cheat + description:Infinite health + code:SGKTSGVG + cheat + description:Infinite lives + code:SXEETAVG + cheat + description:Infinite oxygen + code:SKVXYOVK + cheat + description:Infinite health (alt) + code:00F6:07 + cheat + description:Infinite lives (alt) + code:00F5:07 + cheat + description:Infinite Oxygen (alt) + code:0435:FF + cheat + description:Infinite Fuse + code:04A2:80 + +cartridge sha256:6b2004f30e7de67dfb86db7446f2204695a3a9b9b367bacf401dbf14bb1a74f2 + title:Trog! (USA) + cheat + description:Infinite lives + code:XTXATOVS + +cartridge sha256:a5ae39359aa5b16961a98a7aaeeb278787382d5282ee80b5b3a2de954283ebb7 + title:Trojan (USA) + cheat + description:Infinite health - both players + code:SZVSZXVK + cheat + description:Infinite health - both players (alt) + code:NNUZGKYU+NYVNEKYU + cheat + description:Infinite time + code:GXEPGKVS + cheat + description:One hit kills + code:VTESLOSX + cheat + description:Hit anywhere + code:GZOXYYEL+AAKENATI+AANNIKLP+AAOZLYIZ+AAVAXALG+AEENPKYA+AENIEUAP+AEUNIUUI+AEUYPLNT+AEVIULIZ + cheat + description:Keep High-jump Boots on pick-up + code:SXKVKXVK + cheat + description:Always have High-jump Boots + code:AENIAUYP + cheat + description:Multi-jump - both players + code:AAUSAUGP+AESIZUEI+GXKIILEY + cheat + description:Start with a health boost + code:YASGUUAE + cheat + description:Start with a super health boost + code:TPSGUUAE + cheat + description:Start with half usual health + code:GASGUUAA + cheat + description:Start with 1 life - P1 + code:PENKXPLA + cheat + description:Start with 1 life - P2 + code:PAOKNZLA + cheat + description:Start with 6 lives - P1 + code:TENKXPLA + cheat + description:Start with 6 lives - P2 + code:TAOKNZLA + cheat + description:Start with 9 lives - P1 + code:PENKXPLE + cheat + description:Start with 9 lives - P2 + code:PAOKNZLE + cheat + description:Start with 187 lives - P1 + code:ENNKXPLA + cheat + description:Start with 196 lives - P2 + code:EYOKNZLA + cheat + description:Start with 100 seconds + code:PASKELZA + cheat + description:Start with 900 seconds + code:PASKELZE + cheat + description:Infinite health (alt) + code:0335:08 + +cartridge sha256:0b5d1465b23e31f24e1caecf1490f97a60deb97ba873a36fa948adb016e9c0d2 + title:Trolls on Treasure Island (USA) (Unl) + cheat + description:Infinite time + code:SIOGUTVE + cheat + description:Only one jewel needed to clear stage + code:EYNINYEI + +cartridge sha256:e2b26560d326cc626736efa2addf1c66f5af77913968fcf5cde738188c4a0132 + title:Twin Cobra (USA) + cheat + description:Infinite lives + code:SZVSGXVK + cheat + description:Infinite Bombs + code:SZNYXOVK + cheat + description:Infinite continues + code:AAKKYTPA + cheat + description:Autofire + code:AAOYVOLP + cheat + description:Keep weapon type after death + code:GZNITZSA + cheat + description:Keep super chargers after death + code:GZNSAZSA + cheat + description:9 Bombs after dying + code:ZANIAZLE + cheat + description:20 Bombs after dying + code:GPNIAZLA + cheat + description:Start with 1 life + code:AEUGZIZA + cheat + description:Start with 6 lives + code:IEUGZIZA + cheat + description:Start with 9 lives + code:AEUGZIZE + cheat + description:Start with 1 life after a continue + code:AANKLTZA + cheat + description:Start with 6 lives after a continue + code:IANKLTZA + cheat + description:Start with 9 lives after a continue + code:AANKLTZE + cheat + description:Start with 9 continues + code:PEOKIIIE + cheat + description:Start with 9 Bombs + code:ZAEGKILE + cheat + description:Start with 20 Bombs + code:GPEGKILA + +cartridge sha256:8eb6aa7818f1cac84af0f91350b167f2884dba45073c9f00510f47d0a38e4192 + title:Twin Eagle (USA) + cheat + description:Infinite lives - P1 + code:SXOSVPVG + cheat + description:Infinite Bombs on pick-up - P1 + code:SXNSXSVK + cheat + description:Infinite Bombs on pick-up - P2 + code:SZSIXNVK + cheat + description:Never lose weapons - P1 + code:EYKVVUSA+YAKVNLKZ + cheat + description:Never lose weapons - P2 + code:ENXVKUSA+YEXVSLSZ + cheat + description:1 life after a continue - P1 + code:PAEKXTLA + cheat + description:4 lives after a continue - P1 + code:GAEKXTLA + cheat + description:7 lives after a continue - P1 + code:YAEKXTLA + cheat + description:Start with 7 lives - both players + code:YEETIPLA + cheat + description:Start with 4 lives - both players + code:GEETIPLA + cheat + description:Start with 1 life - both players + code:PEETIPLA + +cartridge sha256:4b9c46714fa085d61ad1177b72bdaa9428d104a171eb6335a03bf06ad9782389 + title:TwinBee (Japan) + cheat + description:Invincibility + code:0093:10 + +cartridge sha256:ef818c90f326383d13087b6e0131bf36563d76c3c1a3c13821c79368e377cf8d + title:Ufouria - The Saga (Europe) + cheat + description:Invincibility + code:EIVETAEY+EIKELYEY + cheat + description:Start with all characters + code:PESVYNYP+YEVTPYAA + +cartridge sha256:af5ac55d6283b709bcd96889708a6e7ad3c77e3bdd377aae796fd87b4b90dc4b + title:Ultima - Exodus (USA) + cheat + description:Take no damage from most monsters + code:GZUKOGST + cheat + description:No limit on stat points + code:AEOAKVAA + cheat + description:Never lose tools + code:AAXIAPPA + cheat + description:Never lose magic + code:KPVSUZOP + cheat + description:Rapid magic recovery + code:AAUEPYPA+OLUAGYOI + cheat + description:Start with 5 of each item + code:IEOPTPPA + cheat + description:Start with 10 of each item + code:ZEOPTPPE + cheat + description:Start with 40 of each item + code:ENOPTPPA + cheat + description:Start with 35,328 gold + code:XEEOAPGV+PUEPTPAL + cheat + description:Start with 512 gold + code:ZEEOAPGT+PUEPTPAL + cheat + description:Start with 200 gold + code:EKEOAPGV + cheat + description:Start with 75 stat points + code:YKEAUVTZ+LKUAVYZU+LGSOPAZU + cheat + description:Start with 5F stat points + code:LSEAUVTX+YSUAVYZU+YISOPAZU + +cartridge sha256:bb625b8df6ddbeb991bb1cbf9b818a5352dcd4856d84640612b2df66148c442f + title:Ultima - Quest of the Avatar (USA) + cheat + description:Infinite MP + code:OLUZZEOO + cheat + description:Infinite Herbs + code:SUOVNKVS + cheat + description:Infinite Oil + code:SZNLKKVK + cheat + description:Infinite Torches + code:SUEUIXVS + cheat + description:Infinite Gems + code:SXVUGSVK + cheat + description:No random battles + code:SZSTXPSA + cheat + description:Heal costs nothing instead of 70 + code:AEKITITG + cheat + description:Cure poison costs nothing + code:AAVILSZA + cheat + description:Axe costs 1 instead of 225 + code:PAEENYOT + cheat + description:Staff costs 1 instead of 20 + code:PAEEUYGP + cheat + description:Sword costs 144 instead of 400 + code:AAOAXYPA + cheat + description:Bow costs 168 instead of 680 + code:AAEAKYZA + cheat + description:Leather costs 1 instead of 200 + code:PAXAONEG + cheat + description:Chain costs 88 instead of 600 + code:AAXAKYZA + cheat + description:Plate costs 196 instead of 2500 + code:AAXEXNPA + cheat + description:Start with perfect virtues (worthy of Avatarhood) + code:LTVPZIZL + cheat + description:Start with 8336 Gold Pieces + code:AZKPTIPA + cheat + description:Start with 4240 Gold Pieces + code:APKPTIPA + cheat + description:Start with 144 Gold Pieces (for experts) + code:AAKPTIPA + cheat + description:Start with 100 Ash instead of 8 + code:GTXPIVAA + cheat + description:Start with 100 Ginseng instead of 8 + code:GTXPTVAA + cheat + description:Start with 100 Garlic instead of 9 + code:GTXPYVPA + cheat + description:Start with 100 Silkweb instead of 7 + code:GTXOATYA + cheat + description:Start with 100 Moss instead of 8 + code:GTXOPVAA + cheat + description:Start with 100 Pearl instead of 4 + code:GTXOZTGA + cheat + description:Start with 100 Fungus instead of none + code:GTXOLTAA + cheat + description:Start with 100 Manroot instead of none + code:GTXOGTAA + cheat + description:Mage starts with 712 HP + code:ZEVPTIAA + cheat + description:Mage starts with 381 EXP + code:PAOPTTAA + cheat + description:Mage starts with Strength of 32 + code:AXNOIIAP + cheat + description:Fighter starts with Strength of 48 + code:AUNOYSLP + cheat + description:Fighter starts with 255 EXP + code:NYOOPVSK + cheat + description:Fighter starts with 812 HP + code:LEVOZIPA + cheat + description:Fighter starts with 75 MP + code:LKNPYIAE + +cartridge sha256:1e8966fd8c9baf57c514fbf4d67ddd8c1ffd184be164f99342ccdec62def8db2 + title:Ultima - Warriors of Destiny (USA) + cheat + description:Infinite consumable items such as food and torches - May not be able to discard some items + code:SUSTXSVS + cheat + description:A night at the Wayfarer Inn is free + code:AAEZIPZL + cheat + description:At Healer's Herbs - Sulfurous ash is free instead of 1 GP + code:AEUZPAPA + cheat + description:At Healer's Herbs - Ginseng is free instead of 2 GP + code:AEUZGAZA + cheat + description:At Healer's Herbs - Garlic is free instead of 2 GP + code:AEUZYAZA + cheat + description:At Healer's Herbs - An Tym Scroll is free instead of 100 GP + code:AEUXIAGT + cheat + description:At Healer's Herbs - Spellbook is free instead of 150 GP + code:AEKZAAVP + cheat + description:At Healer's Herbs - Spidersilk is free instead of 4 GP + code:AEUXZAGA + cheat + description:From Pendra - Spidersilk is free instead of 4 GP + code:AEEXZAGA + cheat + description:From Pendra - Black Pearl is free instead of 3 GP + code:AEEZYALA + cheat + description:From Pendra - Garlic is free instead of 2 GP + code:AEEZGAZA + cheat + description:From Pendra - Ginseng is free instead of 2 GP + code:AEEZPAZA + cheat + description:From Pendra - Sant Talisman is free instead of 75 GP + code:AEEXIELG + cheat + description:At Iolo's Bows - Bow is free instead of 75 GP + code:AAEXIELG + cheat + description:At Iolo's Bows - Wooden shield is free instead of 25 GP + code:AAEXZEPP + cheat + description:At Iolo's Bows - Dagger is free instead of 3 GP + code:AAEZGALA + cheat + description:At Iolo's Bows - Short sword is free instead of 40 GP + code:AAEZYEAZ + cheat + description:At Iolo's Bows - Crossbow is free instead of 150 GP + code:AAOZAAVP + cheat + description:At Iolo's Bows - Arrow is free instead of 1 GP + code:AAOZTAPA + cheat + description:At Iolo's Bows - Bolt is free instead of 2 GP + code:AAOXPAZA + cheat + description:At Iolo's Bows - Sell Dagger for 2,305 instead of 1 GP + code:PAOZAPAE + cheat + description:At Iolo's Bows - Sell Short sword for 2,848 instead of 20 GP + code:LAOZLPAG + cheat + description:At Iolo's Bows - Sell Wooden shield for 3,850 instead of 10 GP + code:YAOZTPAE + cheat + description:At Iolo's Bows - Magic bow is free instead of 800 GP + code:AAOZLAAZ+AAOZGALA + cheat + description:Start new game with 201 instead of 1,225 GP + code:AESXEZGA + cheat + description:Start new game with 4,297 instead of 1,225 GP + code:AOSXEZGA + cheat + description:Start new game with 32,713 instead of 1,225 GP + code:YNSXEZGE + cheat + description:Infinite Health - Avatar + code:6A06:0F + cheat + description:Infinite Health - Shamino + code:6A07:0F + cheat + description:Infinite Health - Iolo + code:6A08:0F + +cartridge sha256:f4de2a91acb2eb3024fb75231859a30c130c0169be0e6ad24330805c8f766e03 + title:Ultimate Stuntman, The (USA) (Unl) + cheat + description:Infinite time + code:SXNSYXVK + cheat + description:Infinite 'Crez' weapon until end of stage + code:SXXSNUVK + cheat + description:Minimum damage taken + code:OVUZKPSV+PEUZSONY + cheat + description:Don't lose a life on Ground Pursuit, Boat and Hang Glider stages + code:GXUAOKVK + cheat + description:9 seconds on clock pick-up + code:PEXXSATE + cheat + description:Full energy on pick-up + code:AEOZXPZA + cheat + description:Shield lasts longer on Human Fly stages + code:NYXXVVAN + cheat + description:Shield lasts a shorter time on Human Fly stages + code:AGXXVVAY + cheat + description:Don't lose a life against end-of-stage bosses and on street combat stages + code:SXNXKNVK + cheat + description:Don't lose a life on Human Fly stages + code:SXXUXSVK + cheat + description:Start with 1 life (first credit only) + code:AENVNGZA + cheat + description:Start with 6 lives (first credit only) + code:IENVNGZA + cheat + description:Start with 9 lives (first credit only) + code:AENVNGZE + +cartridge sha256:c7ad19e926809adc47c0b44c852e19be7a95e7235ee58cb753e68d7cdee9c89c + title:Uncanny X-Men, The (USA) + cheat + description:Infinite life + code:SXEEXIST + cheat + description:Half life - Wolverine + code:GVUZPOEG + cheat + description:Half life - Cyclops + code:GVUZYOEG + cheat + description:Half life - Nightcrawler + code:PKUXIPXA + cheat + description:Half life - Iceman + code:YSKZLOVU + cheat + description:Half life - Colossus + code:YNKXPONN + cheat + description:Half life - Storm + code:ASKXYPEZ + +cartridge sha256:018f8a4f35d15af7891070cbfe6232791d603e92cbd95a49527e80f3825e770d + title:Untouchables, The (USA) (Rev B) + cheat + description:Infinite energy + code:0092:40 + cheat + description:Infinite ammo + code:00C6:02+00C8:02 + cheat + description:Infinite time + code:009A:09 + +cartridge sha256:9048cc77abdfd688395b2f8d1889d3d295d378c649cccbdf79f364fc73217051 + title:Untouchables, The (USA) (Rev A) + cheat + description:Infinite energy on scenes 1 and 4 + code:SLOEAGVI + cheat + description:Infinite energy on scene 2 + code:SXKAATVG + cheat + description:Infinite time on scenes 1 and 4 + code:SXUAZGVG + cheat + description:More time on scene 1 + code:GEXELPZA + cheat + description:Less time on scene 1 + code:PEXELPZA + cheat + description:More time on scene 2 + code:TAXELAGA + cheat + description:Less time on scene 2 + code:ZAXELAGA + cheat + description:More time on scene 3 + code:TAXEYAGA + cheat + description:Less time on scene 3 + code:ZAXEYAGA + cheat + description:More time on scene 5 + code:TAXAPAIA + cheat + description:Less time on scene 5 + code:LAXAPAIA + cheat + description:More time on scene 7 + code:ZAOEAAPA + cheat + description:More ammo picked up on scene 2 + code:AZNETGAP + cheat + description:Less ammo picked up on scene 2 + code:IANETGAP + cheat + description:More ammo picked up on scene 7 + code:PAOEGATE + cheat + description:Start on scene 2 + code:AAXKTEGA + cheat + description:Start on scene 3 + code:ZAXKTEGA + cheat + description:Start on scene 4 + code:GAXKTEGA + cheat + description:Start on scene 5 + code:TAXKTEGA + cheat + description:Start on scene 7 + code:ZAXKTEGE + cheat + description:Infinite energy + code:0092:40 + cheat + description:Infinite ammo + code:00C6:02+00C8:02 + cheat + description:Infinite time + code:009A:09 + +cartridge sha256:43198592f96005c1492165d5af8d41859dc164a99e39e37eff264ae5e0c63b75 + title:Untouchables, The (USA) + cheat + description:Infinite energy on scenes 1 and 4 + code:SLOEAGVI + cheat + description:Infinite energy on scene 2 + code:SXKAATVG + cheat + description:Infinite time on scenes 1 and 4 + code:SXUAZGVG + cheat + description:More time on scene 1 + code:GEXELPZA + cheat + description:Less time on scene 1 + code:PEXELPZA + cheat + description:More time on scene 2 + code:TAXELAGA + cheat + description:Less time on scene 2 + code:ZAXELAGA + cheat + description:More time on scene 3 + code:TAXEYAGA + cheat + description:Less time on scene 3 + code:ZAXEYAGA + cheat + description:More time on scene 5 + code:TAXAPAIA + cheat + description:Less time on scene 5 + code:LAXAPAIA + cheat + description:More time on scene 7 + code:ZAOEAAPA + cheat + description:More ammo picked up on scene 2 + code:AZNETGAP + cheat + description:Less ammo picked up on scene 2 + code:IANETGAP + cheat + description:More ammo picked up on scene 7 + code:PAOEGATE + cheat + description:Start on scene 2 + code:AAXKTEGA + cheat + description:Start on scene 3 + code:ZAXKTEGA + cheat + description:Start on scene 4 + code:GAXKTEGA + cheat + description:Start on scene 5 + code:TAXKTEGA + cheat + description:Start on scene 7 + code:ZAXKTEGE + cheat + description:Infinite energy + code:0092:40 + cheat + description:Infinite ammo + code:00C6:02+00C8:02 + cheat + description:Infinite time + code:009A:09 + +cartridge sha256:7255ab27932f7c07fa61c230a51342b0441ea9b24ba094ae3129ec7453de2449 + title:Urban Champion (World) + cheat + description:Infinite time + code:GZOTZLVG + cheat + description:Powerful quick punches + code:AEEIZGGE + cheat + description:Super powerful quick punch + code:TOEIZGGA + cheat + description:Speed up the timer + code:LENVTZTA + cheat + description:Become a stronger fighter + code:AAXSLLPA + cheat + description:Become a weaker fighter + code:LAXSLLPA + cheat + description:Infinite stamina + code:00CA:99 + +cartridge sha256:433f6bcbd59a9d5916d2209ddeacd39d24810c1ed21a33366171b4991fc7e844 + title:Vice - Project Doom (USA) + cheat + description:Infinite lives + code:SZSKIOVK + cheat + description:Infinite time + code:SZNNNSVK + cheat + description:Infinite grenades + code:SZVYXKVK + cheat + description:Infinite bullets + code:SZKNXKVK + cheat + description:Infinite power + code:SXVYVKSE + cheat + description:10 coins for an extra life + code:ZEOYNGGV + cheat + description:25 coins for an extra life + code:POOYNGGV + cheat + description:20 extra Grenades on pick-up + code:GOENELIA + cheat + description:25 extra Bullets on pick-up + code:POXYXUZE + cheat + description:Start timer for round 1 at 150 + code:VPOEPKXY + cheat + description:Start timer for round 2 at 150 + code:VPUAZKXY + cheat + description:Start with 99 grenades + code:LTNNXLIA + +cartridge sha256:8104dc7acdaea42b027b2cc7b05dc6a1ffdba6e74b35581c2bb0250df89a28fa + title:Vindicators (USA) (Unl) + cheat + description:Infinite lives + code:KLUAGTVI + cheat + description:Automatic fuel replenishment + code:VYUKEIVI + cheat + description:Never lose Stars + code:GZOEVXON + cheat + description:Quicker shot re-load + code:ZAUKYTZP + cheat + description:Turbo speed + code:LPKKLVGE + cheat + description:Start with increased shot range + code:AZKGYVAA + cheat + description:Start with 10 Stars + code:VVVAAPSA + cheat + description:Start with 80 Shots + code:AAUKYTZO+VIKGPTEI + cheat + description:Start with 80 Bombs + code:AAUKYTZO+KIKGPTEI + cheat + description:Start with 1 life + code:AAKKYTZA + cheat + description:Start with 6 lives + code:IAKKYTZA + cheat + description:Start with 9 lives + code:AAKKYTZE + +cartridge sha256:2e312fc327c1e569eccf14eee5a00c41f676c1492035d99af0873681da0f034d + title:Volleyball (USA, Europe) + cheat + description:Computer doesn't get points for scoring + code:YEYIAV + cheat + description:3 points - team 1 + code:0063:03 + +cartridge sha256:f38b9681b53008d32813880c2f28a8969a228a4b3b485ce09f7c0a4334f4abcc + title:VS. Castlevania (VS) + cheat + description:Invincibility (blinking) + code:ESOTOPEY + cheat + description:Infinite health + code:SXNVZYSA + cheat + description:Infinite lives + code:SXVKGZVG + +cartridge sha256:60098a93322a9e07a2b164a02e5517bc22664ca33f6323c2ae23a62941ad393b + title:VS. Super Mario Bros. (VS) + cheat + description:Invincibility + code:VONUPOOE+EISTOTEY + cheat + description:Infinite lives + code:SXAOUE + cheat + description:Go to minus world + code:LZPOAY+YIPOZN+YAPOLY + +cartridge sha256:8589b1dc55e04d23e56e864f1b001c6eecf18b7dcb7a0c4a9c4a40cbcc451601 + title:Wacky Races (USA) + cheat + description:Invincibility + code:EINSUPEY+ESUISPEY+ESEKSIEY + cheat + description:Infinite health + code:SKSGSVVK+SKUKUSVK + cheat + description:Infinite health (alt) + code:GXSGSVVK+GZNKVVVK+GXUKUSVK + cheat + description:Don't take most damage + code:GXSGSVVK + cheat + description:Infinite lives + code:SASSZEVK+SEKIYEVK + cheat + description:Infinite lives (alt) + code:APSIGESZ+AASIIEIS + cheat + description:Infinite Bones after obtaining one + code:SXOILNSE + cheat + description:Go straight to level boss + code:XNUVKIKG + cheat + description:Start at race 1, end of stage 1 + code:EKUVKIKK + cheat + description:Start at race 1, end of stage 2 + code:NKUVKIKK + cheat + description:Start at race 1, end of stage 3 + code:KSUVKIKG + cheat + description:Start at race 2, end of stage 1 + code:ESUVVIVS + cheat + description:Start at race 2, end of stage 2 + code:KSUVVIVS + cheat + description:Start at race 2, end of stage 3 + code:EVUVVIVI + cheat + description:Start at race 3, end of stage 1 + code:KVKTEIXT + cheat + description:Start at race 3, end of stage 2 + code:EVKTEIXV + cheat + description:Start at race 3, end of stage 3 + code:KVKTEIXV + cheat + description:Start at race 3, end of stage 4 + code:ENKTEIXT + cheat + description:Start with 1 life + code:AAKVEIZA + cheat + description:Start with 5 lives + code:GAKVEIZA + cheat + description:Start with 7 lives + code:TAKVEIZA + cheat + description:Start with 9 lives + code:AAKVEIZE + cheat + description:Start with 6 hearts + code:TASTOILA + cheat + description:Start with 8 hearts + code:AASTOILE + cheat + description:Invincibility (alt) + code:0453:01 + cheat + description:Invincibility (blinking) + code:0452:11 + cheat + description:Infinite health (alt 2) + code:0459:03 + cheat + description:Infinite time + code:00A4:59 + cheat + description:Infinite lives (alt 2) + code:045D:63 + cheat + description:Infinite Gems + code:042F:63 + +cartridge sha256:60667bc0ed1c0c6355f59b5716c678954c5f3915064bdbfbb8e0195f2643eda8 + title:Wall Street Kid (USA) + cheat + description:Infinite money + code:OUSNVLOP + cheat + description:Sart a new game with $16,777,215 + code:NYEELPYE+NYEEZPOX+NYEEPPAX + cheat + description:Infinite money (alt) + code:03E1:FF + +cartridge sha256:c12771e8155b030eff0081bfabd98e57a162d6592899f29dd16f141f0e6e08a3 + title:Wario's Woods (USA) + cheat + description:Infinite time + code:XTNXLOVK + cheat + description:Clear round A data to complete round A and B + code:LTKPOLAA+PGKPVLZG + cheat + description:Each coin gives you a credit + code:PAVOEXTP + cheat + description:Always get blue monsters + code:OZSUNAOU+EYVLEAUL + cheat + description:Always get 1 line of monsters + code:VTSLEESE + cheat + description:Wario doesn't cause ceiling to fall, no enemies fall + code:OXNATNSE + cheat + description:One bomb in Birdo time only + code:XTKXGXVK + cheat + description:Invisible Toad + code:SXOIOASA + cheat + description:Invisible coins + code:ENXPSPEI + cheat + description:Coins worth 5 + code:XVXPSESE + cheat + description:Infinite coins fall + code:XVXOEEVK + cheat + description:Only 1 coin falls + code:VXSOTNVK + cheat + description:No Coins fall + code:EESOTNVG + cheat + description:Diamonds don't form in lesson mode + code:NYSZUSOO + +cartridge sha256:059409954035963f1f13029dfa25468100a8e6a90d9388c4a225f235ade97a45 + title:Wayne's World (USA) + cheat + description:Infinite lives + code:VXKESXVK + cheat + description:Infinite time + code:SXSALOVK + cheat + description:Infinite Worthiness + code:SZSEXUSE + cheat + description:More time in level 1 + code:NNSLYYKU + cheat + description:More time in Donut shop in level 1 + code:NNNLIYZU + cheat + description:Power-up restores all Worthiness + code:AANAKLZA + cheat + description:Power-up worth nothing + code:SZNANUSE + cheat + description:Getting all donuts is worth no extra lives + code:SZOOSUVV + cheat + description:Faster timer + code:YOKEZOLU + cheat + description:Slower timer + code:AVKEZOLL + cheat + description:5 special moves on pick-up + code:IAEZXAGP + cheat + description:40 special moves on pick-up + code:AZEZXAGO + cheat + description:Start with less Worthiness + code:EANEZAEL + cheat + description:Start with much less Worthiness + code:AGNEZAEL + cheat + description:Start with 2 lives + code:PANEYAGA + cheat + description:Start with 8 lives + code:YANEYAGA + cheat + description:Start with 10 lives + code:PANEYAGE + +cartridge sha256:a00db4c89bfd12704c53768b62b4f09d57d28891093447d81a0678b059629e59 + title:WCW World Championship Wrestling (USA) + cheat + description:Always win - P1 + code:EGOZINIP+PAOZTNPA+XTOZYYIE + +cartridge sha256:ab6f1bbcda6f0c0bbe1450b5f2ab2b21a5e01ec39143a455701862965cdbd7b4 + title:Werewolf - The Last Warrior (USA) + cheat + description:Infinite time + code:SZXTTLVG + cheat + description:Only 1 anger point needed to become Super-Werewolf + code:PAENGTIA + cheat + description:Blue "W" won't change you back to a man + code:SZXNPVVK + cheat + description:Gain maximum energy from small hearts + code:ESKNTIKI + cheat + description:Hit anywhere + code:AAVGVYGT+AAVKKNTI+AEXGXNAZ+AEXKEYZZ + cheat + description:Don't lose energy from blue "W" + code:AAUNGVZA+AAUNPVAA + cheat + description:Infinite health - P1 + code:00BC:14 + cheat + description:Infinite time (alt) + code:00BF:F4 + cheat + description:Always Werewolf + code:044E:01+042E:01 + cheat + description:Always Super Werewolf + code:044E:02 + cheat + description:Have Gun in Werewolf form + code:044F:01+044D:01 + +cartridge sha256:a66195e11e38bee9f602abd279b7c04367528380dfa5b915dce0fa6fd272c23c + title:Where's Waldo (USA) + cheat + description:Infinite time + code:AEETLZPA + cheat + description:Guesses cost nothing + code:VTSVYYTE + +cartridge sha256:700ebc3c2dd27420bbdcccb987ba60d3f0680469101353de15a1b2bd565ac701 + title:Who Framed Roger Rabbit (USA) + cheat + description:Invincibility + code:ATKTIPEI+ATVIKLEI+ATXGOPEI+AVOVAIEI + cheat + description:Infinite continues + code:SXKELNVK + cheat + description:Never lose a life except in Punch lines + code:SXVOYIVG + cheat + description:Never lose a life in Punch lines + code:SZSZXYVG + cheat + description:Harder to build strength + code:PAUKXTGA + cheat + description:Strength to full instantly + code:EPUKXTGA + cheat + description:Start with 1 life + code:PESSSYLA + cheat + description:Start with 6 lives + code:TESSSYLA + cheat + description:Start with 9 lives + code:PESSSYLE + +cartridge sha256:b9a4542417439619239cdb2cefd8c7eced2407ba2954f026c0ab1ea7d4def3d3 + title:Whomp 'Em (USA) + cheat + description:Infinite health + code:SZNATPSA + cheat + description:Start with 1 life + code:AEKKGALA + cheat + description:Start with 5 lives + code:LAVKYAAA + cheat + description:Start with 10 lives + code:AAVKYAAE + cheat + description:Don't lose a life from energy loss + code:SXEEZPVG + cheat + description:Creatures can't steal extra lives + code:SXXOUPVG + cheat + description:Keep buffalo headdress for present level + code:SZKEGPVG + cheat + description:Always have buffalo headdress + code:ZAKELOAA + +cartridge sha256:9d875583dbdf80a0631ce4ffb3099064454d80568b5e9fe748a5e850f8fa0161 + title:Widget (USA) + cheat + description:Invincibility + code:ENNVEZEI + cheat + description:Infinite health (except against spikes) + code:SXSLEKSE + cheat + description:Infinite health (only against spikes) + code:SXUVOEVK + cheat + description:Infinite time + code:SXUAVXVK+SXXANXVK + cheat + description:Infinite MP + code:SXXPPVSE + cheat + description:Infinite lives + code:SZUGSXVK + cheat + description:Invincibility (blinking) + code:00B9:01 + cheat + description:Infinite health + code:0581:06 + cheat + description:Infinite lives (alt) + code:04F5:02 + cheat + description:Infinite special + code:058B:06 + +cartridge sha256:adff304553b64384f86f6c2b63571f43972b9d087f92359a1b9b93b54d523542 + title:Wild Gunman (World) (Rev A) + cheat + description:Infinite lives in Gang Mode + code:GZOGVYVG + cheat + description:Infinite ammo in Gang Mode + code:GZNIPAVG + cheat + description:Shoot 5 enemies to finish level + code:IENSUOZA+IEUSSUZA + cheat + description:Start with double normal ammo + code:AXVIEOYA + cheat + description:Start with triple normal ammo + code:AUVIEOYA + cheat + description:Start with half normal ammo + code:AEVIEOYE + cheat + description:Start with 1 life + code:YEUISPLE+PENGVALA + cheat + description:Start with 10 lives + code:ZEUISPLE+ZENGVALE + cheat + description:Start with 15 lives + code:YEUISPLE+YENGVALE + +cartridge sha256:62aec65696ecf24a487b7cdd19bad5cbd19f4229a89a7888634d468c67da378a + title:Wild Gunman (Japan, USA) + cheat + description:Infinite lives in Gang Mode + code:EIAGNY + cheat + description:Infinite ammo in Gang Mode + code:EYTIZA + cheat + description:Shoot 5 enemies to finish level + code:IENSUOZA+IEUSSUZA + cheat + description:Start with double normal ammo + code:AXVIEOYA + cheat + description:Start with triple normal ammo + code:AUVIEOYA + cheat + description:Start with half normal ammo + code:AEVIEOYE + cheat + description:Start with 1 life + code:YEUISPLE+PENGVALA + cheat + description:Start with 10 lives + code:ZEUISPLE+ZENGVALE + cheat + description:Start with 15 lives + code:YEUISPLE+YENGVALE + +cartridge sha256:adb1a1a9e853c2390a702e40573d145d08ca6c649cc789e4c8b41fcb63503bb6 + title:Willow (USA) + cheat + description:Infinite magic + code:ZASEGOUI + cheat + description:Don't take any hits + code:TGNILGSA + cheat + description:Start with all items + code:XZKYILKP+AVUOXSOZ + cheat + description:Start at EXP Level 5 + code:GEKISVZA+PNKINTSL + cheat + description:Start at EXP Level 10 + code:PEKISVZE+PNKINTSL + cheat + description:Start at EXP Level 15 + code:TEKISVZE+PNKINTSL + +cartridge sha256:e9539f088b4463e36c2a0d324d6a184fc1ecc3aa26ca4c5675ad9dc948bba5e5 + title:Wing of Madoola, The (Japan) (Sample) + cheat + description:Infinite hits and magic + code:SLUUVYSP + cheat + description:Start with 9999 hits + code:OOKZKPAE+OOKXEPAO + cheat + description:Start with 9999 max hits + code:OOKXKPAE+OOSZEPAO + cheat + description:Start with 9999 magic + code:OOSXEPAO+OOSZKPAE + +cartridge sha256:c3136379fc4e9401dec41be356fd6963e79dd46193c61cc03b59d9935835401f + title:Wizardry - Proving Grounds of the Mad Overlord (USA) + cheat + description:Annointed Mace costs nothing instead of 30 + code:AEVEIPAL + cheat + description:Long Sword costs nothing instead of 25 + code:AAVEIPIZ + cheat + description:Short Sword costs nothing instead of 15 + code:AEXEIPIP + cheat + description:Small Shield costs nothing instead of 20 + code:AEVEIZAZ + cheat + description:Staff costs nothing instead of 10 + code:AAVEIZAP + cheat + description:Dagger costs nothing instead of 15 + code:AEXEIZIA + cheat + description:Robes costs nothing instead of 15 + code:AAVEILIP + cheat + description:S of Pain costs nothing instead of 500 + code:AEVEGYIA + cheat + description:S of Fire costs nothing instead of 500 + code:AAXEKAIA + cheat + description:Body Armor costs nothing instead of 1500 + code:AEXEGYIP + cheat + description:Large Shield costs nothing instead of 40 + code:AAXEILAG + cheat + description:Leather Armor costs nothing instead of 50 + code:AEXEILAI + cheat + description:Chain Mail costs nothing instead of 90 + code:AEVEILEP + cheat + description:Breast Plate costs nothing instead of 200 + code:AAXEGGZA + cheat + description:Helm costs nothing instead of 100 + code:AEXEGGPA + cheat + description:S of Curing costs nothing instead of 500 + code:AEVEGGIA + cheat + description:Rod of Iron costs nothing instead of 3000 + code:AAXEGTAL + cheat + description:Padded Leather costs nothing instead of 1500 + code:AEXEGTIP + cheat + description:Shiny Chain costs nothing instead of 1500 + code:AEVEGTIP + cheat + description:Sturdy Plate costs nothing instead of 1500 + code:AAXEGYIP + cheat + description:Iron Shield costs nothing instead of 1500 + code:AAVEGYIP + cheat + description:Gloves of Copper costs nothing instead of 6000 + code:AEVEKGAT + cheat + description:S of Glass costs nothing instead of 1500 + code:AAVEKLIP + cheat + description:Studly Staff costs nothing instead of 2500 + code:AAXEKPIZ + cheat + description:S of Neutralizing costs nothing instead of 300 + code:AAXEGILA + cheat + description:Plate Mail costs nothing instead of 750 + code:AAVEIGAI+AAVEGGYA + cheat + description:Blade of Biting costs nothing instead of 15000 + code:AEXEGIAI+AEXELIPA + +cartridge sha256:d30e480e7a99b5c3d8fe8faecf0bc0a14a9b163025eca9bf787f600fa927bb89 + title:Wizards & Warriors (USA) (Rev A) + cheat + description:Invincibility + code:EINVTIEY + cheat + description:Invincibility (flashes) + code:AUATPI + cheat + description:Infinite lives + code:GXVUZGVG + cheat + description:Infinite lives (alt) + code:SXVUZGVG + cheat + description:Infinite health + code:GZNVILST + cheat + description:Infinite health (alt) + code:OXOVATES+GEOVPVGU+SEOVZTSZ + cheat + description:Potions last longer + code:NTEINNYK + cheat + description:Meat gives half health + code:PEEVAGZA + cheat + description:Meat gives double health + code:GEEVAGZA + cheat + description:Enter doors without needing a key + code:ALGYPL + cheat + description:Jump higher + code:KYISTO + cheat + description:Jump to the top of the scren + code:KGTITO + cheat + description:Start with 6 lives + code:IAUUKAZA+IAXGGAZA + cheat + description:Start with 9 lives + code:AAUUKAZE+AAXGGAZE + cheat + description:Invincibility (alt) + code:00FC:02 + cheat + description:Infinite health (alt 2) + code:0076:0C + cheat + description:Super-jump (disable if you get stuck) + code:0148:40 + +cartridge sha256:3ba4f6fd63a74338e438df43ddd1195f8913d69c11f6668d3bbf23a2a3cea459 + title:Wizards & Warriors (USA) + cheat + description:Invincibility + code:EINVTIEY + cheat + description:Invincibility (flashes) + code:AUATPI + cheat + description:Infinite lives + code:GXVUZGVG + cheat + description:Infinite lives (alt) + code:SXVUZGVG + cheat + description:Infinite health + code:GZNVILST + cheat + description:Infinite health (alt) + code:OXOVATES+GEOVPVGU+SEOVZTSZ + cheat + description:Potions last longer + code:NTEINNYK + cheat + description:Meat gives half health + code:PEEVAGZA + cheat + description:Meat gives double health + code:GEEVAGZA + cheat + description:Enter doors without needing a key + code:ALGYPL + cheat + description:Jump higher + code:KYISTO + cheat + description:Jump to the top of the scren + code:KGTITO + cheat + description:Start with 6 lives + code:IAUUKAZA+IAXGGAZA + cheat + description:Start with 9 lives + code:AAUUKAZE+AAXGGAZE + cheat + description:Invincibility (alt) + code:00FC:02 + cheat + description:Infinite health (alt 2) + code:0076:0C + cheat + description:Super-jump (disable if you get stuck) + code:0148:40 + +cartridge sha256:2fa3ee5f9ef17dcd63f2f3936dc79b95a71f9e58521080250d4b4e7efbd471d2 + title:Wizards & Warriors III - Kuros...Visions of Power (USA) + cheat + description:Infinite keys + code:SXXNITVG + cheat + description:Infinite gold + code:EYYYYY + cheat + description:Shopkeeper sometimes forgets to charge + code:SZNYZNSE + cheat + description:Infinite lives + code:SXVTGLVG + cheat + description:Infinite lives (except boss stages) + code:SXNTPLVG + cheat + description:Coins worth 25 + code:POSAGGZU + cheat + description:Coins worth 100 + code:GVSAGGZL + cheat + description:Coins worth 255 + code:NNSAGGZU + cheat + description:Bags worth 5 + code:IESAZKZA + cheat + description:Bags worth 50 + code:ZUSAZKZA + cheat + description:Bags worth 255 + code:NNSAZKZE + cheat + description:Less health after death (except boss stages) + code:AGELLZEA + cheat + description:More health after death (except boss stages) + code:ELELLZEA + cheat + description:Start with Less health + code:AGKZGYEA + cheat + description:Start with More health + code:ELKZGYEA + cheat + description:Start with very little life force + code:PAKZGYEA + cheat + description:Start with about half life force + code:AGKZGYEA + cheat + description:Start with 2 lives + code:PAXXPYLA + cheat + description:Start with 7 lives + code:TAXXPYLA + cheat + description:Start with 10 lives + code:PAXXPYLE + cheat + description:Invincibility + code:008B:2B + cheat + description:Infinite health + code:00EB:80 + cheat + description:Infinite Keys + code:0087:02 + cheat + description:Infinite money + code:0669:09 + cheat + description:One hit kills on most enemies/bosses + code:049D:01+049E:01+049F:01+04A0:01+04A1:01 + cheat + description:Have the Orb in slot 1 (enable then disable) + code:0657:01 + cheat + description:Have the Orb in slot 2 (enable then disable) + code:0658:01 + cheat + description:Have the Orb in slot 3 (enable then disable) + code:0659:01 + cheat + description:Have the Orb in slot 4 (enable then disable) + code:065A:01 + cheat + description:Have the Scepter in slot 1 (enable then disable) + code:0657:02 + cheat + description:Have the Scepter in slot 2 (enable then disable) + code:0658:02 + cheat + description:Have the Scepter in slot 3 (enable then disable) + code:0659:02 + cheat + description:Have the Scepter in slot 4 (enable then disable) + code:065A:02 + cheat + description:Have the Coin in slot 1 (enable then disable) + code:0657:03 + cheat + description:Have the Coin in slot 2 (enable then disable) + code:0658:03 + cheat + description:Have the Coin in slot 3 (enable then disable) + code:0659:03 + cheat + description:Have the Coin in slot 4 (enable then disable) + code:065A:03 + cheat + description:Have the Chalice in slot 1 (enable then disable) + code:0657:04 + cheat + description:Have the Chalice in slot 2 (enable then disable) + code:0658:04 + cheat + description:Have the Chalice in slot 3 (enable then disable) + code:0659:04 + cheat + description:Have the Chalice in slot 4 (enable then disable) + code:065A:04 + cheat + description:Have the Amulet in slot 1 (enable then disable) + code:0657:05 + cheat + description:Have the Amulet in slot 2 (enable then disable) + code:0658:05 + cheat + description:Have the Amulet in slot 3 (enable then disable) + code:0659:05 + cheat + description:Have the Amulet in slot 4 (enable then disable) + code:065A:05 + cheat + description:Have the Crown in slot 1 (enable then disable) + code:0657:06 + cheat + description:Have the Crown in slot 2 (enable then disable) + code:0658:06 + cheat + description:Have the Crown in slot 3 (enable then disable) + code:0659:06 + cheat + description:Have the Crown in slot 4 (enable then disable) + code:065A:06 + cheat + description:Have the Crown Jewel 1 in slot 1 (enable then disable) + code:0657:07 + cheat + description:Have the Crown Jewel 1 in slot 2 (enable then disable) + code:0658:07 + cheat + description:Have the Crown Jewel 1 in slot 3 (enable then disable) + code:0659:07 + cheat + description:Have the Crown Jewel 1 in slot 4 (enable then disable) + code:065A:07 + cheat + description:Have the Crown Jewel 2 in slot 1 (enable then disable) + code:0657:08 + cheat + description:Have the Crown Jewel 2 in slot 2 (enable then disable) + code:0658:08 + cheat + description:Have the Crown Jewel 2 in slot 3 (enable then disable) + code:0659:08 + cheat + description:Have the Crown Jewel 2 in slot 4 (enable then disable) + code:065A:08 + cheat + description:Have the Crown Jewel 3 in slot 1 (enable then disable) + code:0657:09 + cheat + description:Have the Crown Jewel 3 in slot 2 (enable then disable) + code:0658:09 + cheat + description:Have the Crown Jewel 3 in slot 3 (enable then disable) + code:0659:09 + cheat + description:Have the Crown Jewel 3 in slot 4 (enable then disable) + code:065A:09 + cheat + description:Have the Crown Jewel 4 in slot 1 (enable then disable) + code:0657:0A + cheat + description:Have the Crown Jewel 4 in slot 2 (enable then disable) + code:0658:0A + cheat + description:Have the Crown Jewel 4 in slot 3 (enable then disable) + code:0659:0A + cheat + description:Have the Crown Jewel 4 in slot 4 (enable then disable) + code:065A:0A + cheat + description:Have the Bronze Knight Statue in slot 1 (enable then disable) + code:0657:0B + cheat + description:Have the Bronze Knight Statue in slot 2 (enable then disable) + code:0658:0B + cheat + description:Have the Bronze Knight Statue in slot 3 (enable then disable) + code:0659:0B + cheat + description:Have the Bronze Knight Statue in slot 4 (enable then disable) + code:065A:0B + cheat + description:Have the Silver Knight Statue in slot 1 (enable then disable) + code:0657:0C + cheat + description:Have the Silver Knight Statue in slot 2 (enable then disable) + code:0658:0C + cheat + description:Have the Silver Knight Statue in slot 3 (enable then disable) + code:0659:0C + cheat + description:Have the Silver Knight Statue in slot 4 (enable then disable) + code:065A:0C + cheat + description:Have the Gold Knight Statue in slot 1 (enable then disable) + code:0657:0D + cheat + description:Have the Gold Knight Statue in slot 2 (enable then disable) + code:0658:0D + cheat + description:Have the Gold Knight Statue in slot 3 (enable then disable) + code:0659:0D + cheat + description:Have the Gold Knight Statue in slot 4 (enable then disable) + code:065A:0D + cheat + description:Have the Bronze Thief Statue in slot 1 (enable then disable) + code:0657:0E + cheat + description:Have the Bronze Thief Statue in slot 2 (enable then disable) + code:0658:0E + cheat + description:Have the Bronze Thief Statue in slot 3 (enable then disable) + code:0659:0E + cheat + description:Have the Bronze Thief Statue in slot 4 (enable then disable) + code:065A:0E + cheat + description:Have the Silver Thief Statue in slot 1 (enable then disable) + code:0657:0F + cheat + description:Have the Silver Thief Statue in slot 2 (enable then disable) + code:0658:0F + cheat + description:Have the Silver Thief Statue in slot 3 (enable then disable) + code:0659:0F + cheat + description:Have the Silver Thief Statue in slot 4 (enable then disable) + code:065A:0F + cheat + description:Have the Gold Thief Statue in slot 1 (enable then disable) + code:0657:10 + cheat + description:Have the Gold Thief Statue in slot 2 (enable then disable) + code:0658:10 + cheat + description:Have the Gold Thief Statue in slot 3 (enable then disable) + code:0659:10 + cheat + description:Have the Gold Thief Statue in slot 4 (enable then disable) + code:065A:10 + cheat + description:Have the Bronze Wizard Statue in slot 1 (enable then disable) + code:0657:11 + cheat + description:Have the Bronze Wizard Statue in slot 2 (enable then disable) + code:0658:11 + cheat + description:Have the Bronze Wizard Statue in slot 3 (enable then disable) + code:0659:11 + cheat + description:Have the Bronze Wizard Statue in slot 4 (enable then disable) + code:065A:11 + cheat + description:Have the Silver Wizard Statue in slot 1 (enable then disable) + code:0657:12 + cheat + description:Have the Silver Wizard Statue in slot 2 (enable then disable) + code:0658:12 + cheat + description:Have the Silver Wizard Statue in slot 3 (enable then disable) + code:0659:12 + cheat + description:Have the Silver Wizard Statue in slot 4 (enable then disable) + code:065A:12 + cheat + description:Have the Gold Wizard Statue in slot 1 (enable then disable) + code:0657:13 + cheat + description:Have the Gold Wizard Statue in slot 2 (enable then disable) + code:0658:13 + cheat + description:Have the Gold Wizard Statue in slot 3 (enable then disable) + code:0659:13 + cheat + description:Have the Gold Wizard Statue in slot 4 (enable then disable) + code:065A:13 + +cartridge sha256:2d62114f3f139e8dd01c3e6e56d83a848a236ebb0c146fac5d372ba40ae456d5 + title:Wolverine (USA) + cheat + description:No enemies + code:ISISYU + cheat + description:Infinite lives - both players + code:GZEXAOVK + cheat + description:Mega-jump + code:AXXLNUIE + cheat + description:Claws use up no health + code:AAXGYLPA + cheat + description:Super speed + code:KYXUVUVN+GAUUELZA + cheat + description:Take less damage from bullets + code:ZAXLISAA+ZAEKAKAA + cheat + description:Start each new life as a berserker + code:AGNIZAAA + cheat + description:Start with 1 life - P1 + code:PEUSZALA + cheat + description:Start with 6 lives - P1 + code:TEUSZALA + cheat + description:Start with 9 lives - P1 + code:PEUSZALE + cheat + description:Start with 1 life - P2 + code:PEVIYALA + cheat + description:Start with 6 lives - P2 + code:TEVIYALA + cheat + description:Start with 9 lives - P2 + code:PEVIYALE + cheat + description:Start on stage 2 - P1 + code:PEXIZAAA + cheat + description:Start on stage 4 - P1 + code:LEXIZAAA + cheat + description:Start on stage 6 - P1 + code:IEXIZAAA + cheat + description:Start on stage 8 - P1 + code:YEXIZAAA + cheat + description:Start on stage 2 - P2 + code:PEKSYAAA + cheat + description:Start on stage 4 - P2 + code:LEKSYAAA + cheat + description:Start on stage 6 - P2 + code:IEKSYAAA + cheat + description:Start on stage 8 - P2 + code:YEKSYAAA + cheat + description:Infinite health + code:00CD:1E + cheat + description:Infinite lives + code:04DA:03 + +cartridge sha256: + title:World Hero (Unl) [!] + cheat + description:Hit anywhere + code:AASSVEIG+AGUTUYPL+AZUTSNNV+ETUTXYSG + +cartridge sha256:3950d679fd6bbd5b59b720ef0284cb916f916a985103ccec60de2f256bcd8786 + title:Wrath of the Black Manta (USA) (Rev A) + cheat + description:Invincibility (blinking) + code:0589:FA + cheat + description:Start on stage 2 + code:054A:01 + cheat + description:Start on stage 3 + code:054A:03 + cheat + description:Start on stage 4 + code:054A:04 + cheat + description:Start on stage 5 + code:054A:05 + +cartridge sha256:545a5533481f4f7bd8f7e9d6c7ccad9195f870522d7d2a9d83c18958804da008 + title:Wrath of the Black Manta (USA) + cheat + description:Take no damage from most enemies + code:SXSLXUVK + cheat + description:Never die from falling off screen + code:SZVOKEVK + cheat + description:Mega-jump when stationary + code:GZUZSUSO + cheat + description:Start with extra energy + code:AEOAZTLE + cheat + description:Start with 1 life + code:AEOAYTZA + cheat + description:Start with 6 lives + code:IEOAYTZA + cheat + description:Start with 9 lives + code:AEOAYTZE + cheat + description:Invincibility (blinking) + code:0589:FA + cheat + description:Start on stage 2 + code:054A:01 + cheat + description:Start on stage 3 + code:054A:03 + cheat + description:Start on stage 4 + code:054A:04 + cheat + description:Start on stage 5 + code:054A:05 + +cartridge sha256:f1eb29dd1c7b2b29f4932df853f32a7560bbfe64997281aa79f61ba9f131fb17 + title:Wrecking Crew (World) + cheat + description:Invincibility + code:ATNKYZAZ + cheat + description:Infinite lives - P1 + code:SXGXGL + cheat + description:Infinite lives - P2 + code:SXIXZL + cheat + description:Annoying guy doesn't bother you + code:SZXILXSO+SXKILOSO + cheat + description:Start with Golden Hammer + code:VVUXGPSA + cheat + description:Start with 1 life - both players + code:PELXYP + cheat + description:Start with 10 lives - both players + code:PELXYO + cheat + description:Start with 15 lives - both players + code:YELXYO + cheat + description:Start with 250 lives + code:ENLXYO + +cartridge sha256:a0354fb9c1c29e25b8bd2bd45735e8af2263cde66b56cc2e61eb5d9295a42de1 + title:Wurm - Journey to the Center of the Earth! (USA) + cheat + description:Infinite fuel + code:SZSGYNSE + cheat + description:Infinite shields and life + code:SXNGZTSA + cheat + description:Start on Act 2 - Dyna Crystal + code:ZEXITGPA + cheat + description:Start on Act 3 - Magma Falls + code:LEXITGPA + cheat + description:Start on Act 4 - Ziggy + code:GEXITGPA + cheat + description:Start on Act 5 - Dual Duel + code:IEXITGPA + +cartridge sha256:e5de4656729ffa37f7f6afdccb7c207ca7b867768369cc1a2817626919bff8dc + title:WWF King of the Ring (USA) + cheat + description:Infinite health - both players + code:VZUUIVOO + cheat + description:Infinite health - P1 + code:0168:BF + cheat + description:No health - P2 + code:0194:00 + +cartridge sha256:a6f98e57ffb4544152138f109b00d1016ae957f7d842f29b41e118045fd54056 + title:WWF Wrestlemania (USA) + cheat + description:Infinite health - P1 + code:OZXGNYEU+XGXKEYZE+SAXKOYVT + cheat + description:One hit drains all health + code:ENOGVIEP + cheat + description:Opponent is idle after a body slam + code:SXZTSO + cheat + description:Countdown starts on 3 + code:LAKTLLPA + cheat + description:1 minute tournament rounds + code:PAXGXPLA + cheat + description:6 minute tournament rounds + code:TAXGXPLA + cheat + description:9 minute tournament rounds + code:PAXGXPLE + +cartridge sha256:89df74e7b275929c91a64580c5b1733bee26bcaf3a923dcca9fffdda835b2964 + title:WWF Wrestlemania Challenge (USA) + cheat + description:Pin count extended to 9 seconds + code:ZEELLGGE + cheat + description:10-count reduced to 5 seconds + code:TESGYOLA + cheat + description:All counts slower + code:IVNKGOGL + cheat + description:All counts faster + code:YONKGOGU + +cartridge sha256:b0e4bcb63416c32fc247ff8afc28915ba15906a9b02aaed77a41e8109eab91fc + title:WWF Wrestlemania Steel Cage Challenge (USA) + cheat + description:P1 cannot lose (constant 1 count) + code:VXSASUVK + cheat + description:Infinite energy refills (press select when energy is low) + code:SUXIXNSO + cheat + description:1 minute tournament rounds + code:PAXGXPLA + cheat + description:6 minute tournament rounds + code:TAXGXPLA + cheat + description:9 minute tournament rounds + code:PAXGXPLE + +cartridge sha256:4b11689be770a7dd6ef560568ba1fd70d6c585babedd8c9088769a0d63d89cf1 + title:Xenophobe (USA) + cheat + description:Infinite health - both players + code:AAKIYNUT + cheat + description:Increase starting health - both players + code:LASIZOPA + cheat + description:More health - P1 + code:LAVILONY+AIVIIOGI + cheat + description:No health pick-ups allowed + code:SXNITVOO + cheat + description:Start on level 2 + code:TAKSAPYA + cheat + description:Start on level 3 + code:IAKSAPYA + cheat + description:Start on level 4 + code:GAKSAPYA + cheat + description:Start on level 5 + code:LAKSAPYA + cheat + description:Infinite health - P1 (one's digit) + code:0753:09 + cheat + description:Infinite health - P1 (ten's digit) + code:0752:0A + cheat + description:Infinite health - P1 (hundred's digit) + code:0751:09 + cheat + description:Infinite health - P1 (thousand's digit) + code:0750:09 + cheat + description:Infinite health - P2 (one's digit) + code:0757:0B + cheat + description:Infinite health - P2 (ten's digit) + code:0756:0B + cheat + description:Infinite health - P2 (hundred's digit) + code:0755:09 + cheat + description:Infinite health - P2 (thousand's digit) + code:0754:09 + cheat + description:Character modifier - Dr. Kwack + code:0795:00 + cheat + description:Character modifier - Mr. Frogg + code:0795:01 + cheat + description:Character modifier - Dr. Zordirz + code:0795:02 + +cartridge sha256:9112f5b30c8a8d0dbd967973e84357860b5f0cf37ab3511b39128b5d37fa86ff + title:Xevious - The Avenger (USA) + cheat + description:Invincibility + code:SEKYKISZ + cheat + description:Infinite lives + code:SZLNZY + cheat + description:Start with 1 life + code:PAZYOG + cheat + description:Start with 6 lives + code:TAZYOG + cheat + description:Start with 9 lives + code:PAZYOK + +cartridge sha256:2508e4eada73f233b2df86af2248a370b2d40ec2de590c8886a8750ddfb5b79c + title:Xexyz (USA) + cheat + description:Immune to enemy bullets + code:OTNGGYSV + cheat + description:Immune to monsters + code:OTNGGTSV + cheat + description:Infinite lives + code:SZEXTKVK + cheat + description:Become a whirlwind on new life + code:VTOXAKSE + cheat + description:1 life after continue + code:PAUXLILA + cheat + description:Start with 1 life + code:PAUZTZLA + cheat + description:Start with 6 lives + code:TAUZTZLA + cheat + description:Start with 9 lives + code:PAUZTZLE + cheat + description:Start with and keep foot-wing + code:AAOLPNAA + +cartridge sha256:1f349392d49c60c3e52a06be6ab4d914bf71ffd5b73857964ec9d604806b131b + title:Xybots (USA) (Proto) (Unl) + cheat + description:Infinite lives and second shots + code:SUEYIUVS + cheat + description:Infinite Keys - both players + code:SZEPGEVS + cheat + description:Infinite money - both players + code:SUEAVOSO + cheat + description:Infinite Slow Energy Drain and Zap power + code:SZVVUOSO + cheat + description:Infinite Warning Arrows and Level Mappers + code:SXUULVSO + cheat + description:Infinite Enemy Mappers and Guard Mapper + code:OLSTEOOO + cheat + description:Start with 6 lives and 6 second shots + code:TTSVGPZP + cheat + description:Start with 3 Slow Energy Drain and 4 Zap power - P1 + code:GZSTZPZA + cheat + description:Start with 3 Slow Energy Drain and 4 Zap power - P2 + code:GZSTYPZP + cheat + description:Start with 6 Warning Arrows and Level Mappers + code:TTVTGPPZ + cheat + description:Start with 6 Enemy Mappers and have Guard Mapper + code:TPVVGPPA + cheat + description:Start with 99 Keys, $99 and 2,544,300 points + code:LVXVGGAA + cheat + description:Start with 4 extra Speed, extra Armor, extra Shot Speed, extra Shot Power and Wide Shot + code:GGUTAPAA + cheat + description:Start at last level + code:TLNTTPPA + +cartridge sha256:0624c93899a588232f9193db0d560291b15636727813a4cd6c3dab8b7f74badb + title:Yie Ar Kung-Fu (Japan) (Rev 1.4) + cheat + description:Infinite health + code:SUOIUIVT + cheat + description:Infinite health (alt) + code:00DB:00 + +cartridge sha256:dbe10104fc90c36ff7c95424cb192dfd9619fb7c1238bbae8da87e0bc9cc5a4e + title:Yie Ar Kung-Fu (Japan) (Rev 1.2) + cheat + description:Invincible against punches and kicks + code:SZUIXISA + cheat + description:Tao does not throw fireballs + code:SXNVLTSA + cheat + description:Chen does not hit you with his chain + code:SXNTSASA + cheat + description:Lang does not throw shurikens + code:OZVVATEK + cheat + description:Bonus doesn't end when you're hit with a sword or fan + code:AVOSOVOZ + cheat + description:Infinite health + code:00DB:00 + +cartridge sha256:62a3551ce546fa7df5fd4970e725e36f1ca269be62b1e33f92546d6e649b8371 + title:Yo! Noid (USA) + cheat + description:Invincibility + code:AVZUSZ + cheat + description:Invincibility (alt) + code:SZULPTAX + cheat + description:Infinite time + code:SXXLIGVG + cheat + description:Infinite lives + code:SXKTTUVK+SXKVPUVK + cheat + description:More magic from small scrolls + code:IAKUVGPA + cheat + description:Multi-mega-jumps + code:AEUGSKTZ + cheat + description:1 continue + code:PAXSNZLA + cheat + description:6 continues + code:TAXSNZLA + cheat + description:Start with 1 life + code:AUUIVPZL+AKUSOPZG + cheat + description:Start with 6 lives + code:IUUIVPZL+IKUSOPZG + cheat + description:Start with 9 lives + code:PUUIVPZU+PKUSOPZK + cheat + description:Start on stage 2 + code:ZEVSKPPA + cheat + description:Start on stage 4 + code:GEVSKPPA + cheat + description:Start on stage 6 + code:TEVSKPPA + cheat + description:Start on stage 8 + code:AEVSKPPE + cheat + description:Start on stage 10 + code:ZEVSKPPE + cheat + description:Start on stage 12 + code:GEVSKPPE + +cartridge sha256:56a169bb3a6101057fb278f2febd58cb1dbf056e5aaeb709c51a55ce4cfac20d + title:Yoshi (USA) + cheat + description:Short wait for next characters + code:GOUYPEAZ + cheat + description:Really short wait for next characters + code:ZEUYPEAZ + cheat + description:Really long wait for next characters + code:NNUYPEAX + cheat + description:Freeze characters for a short time (press Down) + code:AVSULYZA + cheat + description:Need only 1 Victory Egg to win + code:PAVAAPLA+PESTAZLA+PEXTZLLA + cheat + description:Need only 2 Victory Eggs to win + code:ZAVAAPLA+ZESTAZLA+ZEXTZLLA + +cartridge sha256:fd4884c98d9412eb362c0654c8f5475e7f24266984f11e19961495c2d642d38a + title:Young Indiana Jones Chronicles, The (USA) + cheat + description:Infinite health + code:XVSEGPSE + cheat + description:Infinite lives + code:SZEOUGVG + cheat + description:Start with 2 + code:PEKSVGLA + cheat + description:Start with 7 lives + code:TEKSVGLA + cheat + description:Start with 10 lives + code:PEKSVGLE + +cartridge sha256:c79202082042baeb3a45e747a1675c9530137f847c357c393270715efc32217e + title:Ys II - Ancient Ys Vanished - The Final Chapter (Japan) + cheat + description:Infinite HP + code:SXOVXISA + cheat + description:Infinite gold + code:SZXELISA+SZUAZISA + cheat + description:Lots of EXP + code:AEOSNSPE+AEXISSZE + cheat + description:Start with all equipment + code:YYKSKIPE + +cartridge sha256:91d281ee84a71483cd9b8e8021222ef509a8c0ea4be0a4fa675140a91b65c2da + title:Yume Koujou Doki Doki Panic (Japan) [b] (FDS) + cheat + description:Multi-jump + code:GZUEITEI + cheat + description:Invincibility + code:0085:FA + cheat + description:Infinite coins + code:062B:09 + cheat + description:Infinite sub-space time + code:04B7:FA + cheat + description:Infinite magic carpet time + code:00B9:FA + cheat + description:All characters can float + code:04C9:FA + cheat + description:Multi-jump (alt) + code:0099:00 + cheat + description:One hit kills on bosses + code:0468:00 + cheat + description:Only 1 Cherry needed for Starman + code:062A:04 + cheat + description:Only 1 big Radish needed for Stopwatch + code:062C:04 + cheat + description:Receive small heart for every enemy defeated + code:04AD:09 + cheat + description:Stopwatch always active + code:04FF:FA + cheat + description:Start on World 2 + code:0635:01 + cheat + description:Start on World 3 + code:0635:02 + cheat + description:Start on World 4 + code:0635:03 + cheat + description:Start on World 5 + code:0635:04 + cheat + description:Start on World 6 + code:0635:05 + cheat + description:Start on World 7 + code:0635:06 + +cartridge sha256:bdc9dfed1b03db470a1453da0252b3e9fcd0869d02a48622476ddaa350e53374 + title:Zanac (USA) + cheat + description:Infinite lives + code:OXEENYVK + cheat + description:Start with Straight Crusher + code:PEOPAGAA + cheat + description:Start with Field Shutter + code:ZEOPAGAA + cheat + description:Start with the Circular + code:LEOPAGAA + cheat + description:Start with the Vibrator + code:GEOPAGAA + cheat + description:Start with the Rewinder + code:IEOPAGAA + cheat + description:Start with the Plasma Flash + code:TEOPAGAA + cheat + description:Start with rapid fire + code:YEOPAGAA + cheat + description:Start with 1 life + code:PEEKOLLA + cheat + description:Start with 6 lives + code:TEEKOLLA + cheat + description:Start with 9 lives + code:PEEKOLLE + cheat + description:Invincibility + code:0764:00 + +cartridge sha256:4cfc55e1521e58039d502f2a5ff16c233b84c0a05b1048185c75c971f3814c16 + title:Zelda II - The Adventure of Link (USA) + cheat + description:Infinite health + code:XTLTILSV+XTLTTUGE + cheat + description:Almost infinite health + code:XTLTAL + cheat + description:Infinite magic + code:GXNAESON + cheat + description:Infinite magic (alt) + code:SXNASSSE + cheat + description:Infinite magic and health in battle + code:AEYSAU + cheat + description:Infinite lives + code:SZKGKXVK + cheat + description:Infinite Keys after obtaining one + code:SXVIKOVK + cheat + description:Keys not necessary to open doors + code:XVTIUO+XVTIXP + cheat + description:Gain 256 EXP when you defeat an enemy most of the time + code:XTSSTKSE + cheat + description:Gain more than 256 EXP for every EXP + code:PAVIIGAA + cheat + description:Don't lose EXP points while leveling up + code:SZVOUNSE+SZNPKNSE + cheat + description:Hit anywhere (press up if you get stuck at a Palace entrance) + code:ASXTGTEL + cheat + description:Multi-jump + code:SYUPAINY+OZUPISSX+UYUPTSIN+SAUPYIIE+IYUOAIAO+IAUOPIZA + cheat + description:Mega-jump + code:AZUOLIAL + cheat + description:Link can fly (hold A) + code:AAUOLIAL + cheat + description:Swap Shield spell for Fire spell + code:OYKEEVSA+NPKEOVVA + cheat + description:Swap Shield spell for Spell spell + code:LYKEEVSA+VAKEOVVE + cheat + description:Swap Shield spell for Fairy spell + code:LZKEEVSA+OPKEOVVA + cheat + description:Swap Shield spell for Life spell + code:IIKEEVSE+VAKEOVVE + cheat + description:Swap Shield spell for Thunder spell + code:VTKEEVSA+OPKEOVVA + cheat + description:Start with all spells + code:VIEXIVSU + cheat + description:Start with 1 life + code:PASKPLLA + cheat + description:Start with 6 lives + code:TASKPLLA + cheat + description:Start with 9 lives + code:PASKPLLE + cheat + description:Invincibility (disable when fighting your shadow) + code:0518:03 + cheat + description:Infinite health (alt) + code:0774:FF + cheat + description:Infinite magic (alt 2) + code:0773:FF + cheat + description:Infinite lives (alt) + code:0700:04 + cheat + description:Infinite Keys + code:0793:09 + cheat + description:No enemies in overworld + code:0086:00+0087:00+0088:00+0089:00 + cheat + description:Jump spell always on + code:076F:02 + cheat + description:Max sword level + code:0777:FF + cheat + description:Max magic level + code:0778:FF + cheat + description:Max life level + code:0779:FF + cheat + description:Have up/down thrust + code:0796:FF + cheat + description:Have Shield spell + code:077B:01 + cheat + description:Have Jump spell + code:077C:01 + cheat + description:Have Life spell + code:077D:01 + cheat + description:Have Fairy spell + code:077E:01 + cheat + description:Have Fire spell + code:077F:01 + cheat + description:Have Reflect spell + code:0780:01 + cheat + description:Have Spell spell + code:0781:01 + cheat + description:Have Thunder spell + code:0782:01 + cheat + description:Max magic jars + code:0783:08 + cheat + description:Have Boots + code:0788:01 + cheat + description:Have Candle + code:0785:01 + cheat + description:Have Cross + code:078A:01 + cheat + description:Have Flute + code:0789:01 + cheat + description:Have Glove + code:0786:01 + cheat + description:Have Hammer + code:078B:01 + cheat + description:Have Key + code:078C:01 + cheat + description:Have Raft + code:0787:01 + cheat + description:Can enter final palace + code:0794:00 + cheat + description:One hit kill on final boss + code:00C2:01 + +cartridge sha256:939dcb88fce04f9c91e1ce49016b12e301afc4861684576ab5862eada5860db7 + title:Zen - Intergalactic Ninja (USA) + cheat + description:Infinite health + code:GZNLYUSE + cheat + description:Infinite lives + code:SZSPGTVG+SZOZYTVG + cheat + description:9 lives allowed in options menu + code:ZAELNGIE + cheat + description:Slower timer + code:NYNXVTOE + cheat + description:Faster timer + code:YTNXVTOE + cheat + description:Even faster timer + code:YINXVTOE + cheat + description:Zen does increased damage - isometric stages + code:AEUAOLGE + cheat + description:Zen does mega damage - isometric stages + code:GOUAOLGA + cheat + description:Jab attack does more damage - horizontal stages + code:AAKXUIGE + cheat + description:Mega jab attack damage - horizontal stages + code:GPKXUIGA + cheat + description:Fewer hits in shield + code:PAEUGGLA+PAXUNTLA + cheat + description:Double hits in shield + code:TAEUGGLA+TAXUNTLA + cheat + description:Triple hits in shield + code:PAEUGGLE+PAXUNTLE + +cartridge sha256:d0850075065ecbd125a33accc952de5d012527be45aa14a1b8223a9adf1643ae + title:Zoda's Revenge - StarTropics II (USA) + cheat + description:Invincibility + code:VZKZAOSV + cheat + description:Infinite lives + code:SXKVPKVK + cheat + description:Infinite weapons + code:SLUZTSVS + cheat + description:Walk faster - battle mode + code:ZAUXKAPA + cheat + description:Jump faster and further - battle mode + code:PAUXKAAA + cheat + description:Throw Tink's axe further + code:AVKULAAG + cheat + description:1 star gives energy + code:PASZPTIA+PASZITIA + cheat + description:Throw Tink's Axe faster (can't be combined with other Axe code) + code:OYUUAAPG + cheat + description:Tink's Axe splits into 3 little ones when thrown (can't be combined with other Axe code) + code:LGUUAAPG + cheat + description:Throw Tink's splitting-Axe faster (can't be combined with other Axe code) + code:UYUUAAOY + cheat + description:Start with 1 life (Only effective in battle mode on first life) + code:PAVTTZLA + cheat + description:Start with 6 lives (Only effective in battle mode on first life) + code:TAVTTZLA + cheat + description:Start with 9 lives (Only effective in battle mode on first life) + code:PAVTTZLE + +cartridge sha256:91eae4e0e59dadd5de7cdbe71fe57e304d741ae5107928e29e0f6ff8813151a9 + title:Zombie Nation (USA) + cheat + description:Infinite health + code:AVXTEISZ + cheat + description:Infinite continues + code:053B:05 + +cartridge sha256:061d1c3865ad62ae883bb30b9f0071e8f7aa572f15f61bfb91b3a755eeeb5eb0 + title:Zunou Senkan Galg (Japan) + cheat + description:Invincibility + code:ATEEIVAT+ATSKOYSZ + cheat + description:Infinite lives + code:OXNEAAVK + +cartridge sha256:8808783f789ca6413364a7abea240f6f7291b5906026f360ba8cfdd2791fc179 + title:2020 Super Baseball (USA) + cheat + description:Have lots of money - P1 + code:7F80CA:63+7F80CC:63+7F80CB:63 + cheat + description:Have 9 points - P1 + code:7FC13B:09 + cheat + description:Have no outs + code:7FC138:00 + cheat + description:Have no strikes + code:7FC136:00 + cheat + description:Have no balls + code:7FC137:00 + +cartridge sha256:2ffe8828480f943056fb1ab5c3c84d48a0bf8cbe3ed7c9960b349b59adb07f3b + title:3 Ninjas Kick Back (USA) + cheat + description:Invincibility + code:EDEA-1F6B+2DBF-4F6F + cheat + description:Infinite lives + code:C235-C768 + cheat + description:Infinite health + code:7E0A2A:06 + cheat + description:Infinite lives (alt) + code:7E1E51:14 + cheat + description:Infinite time + code:7E1E6B:14 + cheat + description:Infinite Bombs + code:7E1E63:14+7E1E65:14 + cheat + description:Max coins + code:7E1E5B:14+7E1E59:14 + cheat + description:Have throwing weapon + code:7E1E5B:14+7E1E59:14 + cheat + description:Less enemies to pass trials (disable then enable) + code:7E1FE0:02 + +cartridge sha256:4dd631433c867ba920997fd3add2c838b62e70e06e0ef55c53884b8b68b0dd27 + title:7th Saga, The (USA) + cheat + description:Human fighter has 50 HP + code:7417-87AD + cheat + description:Human fighter has 100 HP + code:1017-87AD + cheat + description:Human fighter has 200 HP + code:A617-87AD + cheat + description:Tetujin has 50 HP + code:7416-8FAD + cheat + description:Tetujin has 100 HP + code:1016-8FAD + cheat + description:Tetujin has 200 HP + code:A616-8FAD + cheat + description:Dwarf has 50 HP + code:7419-8D0D + cheat + description:Dwarf has 100 HP + code:1019-8D0D + cheat + description:Dwarf has 200 HP + code:A619-8D0D + cheat + description:Human mage has 50 HP + code:741B-840D + cheat + description:Human mage has 100 HP + code:101B-840D + cheat + description:Human mage has 200 HP + code:A61B-840D + cheat + description:Elf has 50 HP + code:7411-8DAD + cheat + description:Elf has 100 HP + code:1011-8DAD + cheat + description:Elf has 200 HP + code:A611-8DAD + cheat + description:Demon has 50 HP + code:741C-84AD + cheat + description:Demon has 100 HP + code:101C-84AD + cheat + description:Demon has 200 HP + code:A61C-84AD + cheat + description:Alien has 50 HP + code:7415-8F0D + cheat + description:Alien has 100 HP + code:1015-8F0D + cheat + description:Alien has 200 HP + code:A615-8F0D + cheat + description:Human fighter has 20 power + code:F010-8DAD + cheat + description:Tetujin has 20 power + code:F016-84AD + cheat + description:Dwarf has 20 power + code:F019-8F0D + cheat + description:Human mage has 20 power + code:F01B-870D + cheat + description:Elf has 20 power + code:F011-8FAD + cheat + description:Demon has 20 power + code:F01C-87AD + cheat + description:Alien has 20 power + code:F015-840D + cheat + description:Human fighter has 30 MP + code:F310-8D0D + cheat + description:Tetujin has 30 MP + code:F316-840D + cheat + description:Dwarf has 30 MP + code:F319-8DAD + cheat + description:Human mage has 30 MP + code:F31B-84AD + cheat + description:Elf has 30 MP + code:F311-8F0D + cheat + description:Demon has 30 MP + code:F31C-870D + cheat + description:Alien has 30 MP + code:F315-8FAD + cheat + description:Human fighter has 20 speed + code:F010-8F6D + cheat + description:Tetujin has 20 speed + code:F016-876D + cheat + description:Dwarf has 20 speed + code:F019-84DD + cheat + description:Human mage has 20 speed + code:F01C-8DDD + cheat + description:Elf has 20 speed + code:F011-846D + cheat + description:Demon has 20 speed + code:F018-8D6D + cheat + description:Alien has 20 speed + code:F015-87DD + cheat + description:Enemies aren't generated + code:18F6-EDDF + cheat + description:Touching an enemy doesn't cause a battle + code:18F7-EF67 + cheat + description:Sell an item for maximum gold + code:6D87-540D + cheat + description:Get 999 Max HP when you use a 'V Seed' + code:DDC1-7FBD + cheat + description:Get 999 Max MP when you use an 'M Seed' + code:DDC2-7F2D + cheat + description:Get 999 Power when you use a 'P Seed' + code:DDC0-54FD + cheat + description:Get 999 Guard when you use a 'Pr Seed' + code:DDC8-549D + cheat + description:Get 255 Magic when you use an 'I Seed' + code:DDC4-8FBD + cheat + description:Get 255 Speed when you use an 'A Seed' + code:DDCB-8DBD + cheat + description:Human fighter starts with Sword of Anger + code:1B10-870D + cheat + description:Human fighter starts with Sword of Courage + code:1A10-870D + cheat + description:Human fighter starts with Sword of Fire + code:1E10-870D + cheat + description:Dwarf starts with Sword of Nature + code:1C19-87AD + cheat + description:Dwarf starts with Sword of Courage + code:1A19-87AD + cheat + description:Dwarf starts with Sword of Fire + code:1E19-87AD + cheat + description:Human mage starts with petrified staff + code:631C-8FAD + cheat + description:Human mage starts with Rod of Tide + code:6E1C-8FAD + cheat + description:Elf starts with petrified staff + code:6315-8D0D + cheat + description:Elf starts with Staff of Brilliance + code:BF15-8D0D + cheat + description:Demon starts with Sword of Anger + code:1B18-840D + cheat + description:Demon starts with Sword of Despair + code:1218-840D + cheat + description:Demon starts with Sword of Fire + code:1E18-840D + cheat + description:Start with 297 gold + code:4ABD-84AD+DFBD-87DD + cheat + description:Start with 62,708 gold + code:E0BD-84AD+DFBD-87DD + cheat + description:Start with 2000 gold + code:2DBD-84AD+D5BD-87DD + +cartridge sha256:69c5805ad0494703e7d636d3d40d615d33e79bebef9d2cdb4a23b73d44c7b6f9 + title:A.S.P. - Air Strike Patrol (USA) + cheat + description:No damage from enemy fire + code:C22A-CD01+C534-CDD0 + cheat + description:Infinite fuel + code:C2B1-3765 + cheat + description:Infinite flares + code:C237-CFA1 + cheat + description:Infinite missles for F-15 Strike Eagle + code:C2B8-4DA9 + cheat + description:Infinite missles for A-10 Thunderbolt II + code:C2B7-C4D9 + +cartridge sha256:ce164872c4f5814bce04cf0565edcdb5b7969ae95a3b5cd515cfb626b5cde7b3 + title:Aaahh!!! Real Monsters (USA) + cheat + description:Invincibility + code:62BE-0767 + cheat + description:Infinite health + code:C282-04A7 + cheat + description:Infinite Fish + code:C28E-DD67 + cheat + description:Infinite Books + code:82AA-0F04 + cheat + description:Infinite Garbage + code:DD8E-4DD7 + cheat + description:Infinite Scares + code:DDAA-1464 + cheat + description:Infinite lives + code:DDC0-3FDF + cheat + description:Get nothing for each Trash Bag + code:DDC8-0FAF + cheat + description:Get 20 for each Trash Bag + code:4DC8-0FAF + cheat + description:Get 100 for each Trash Bag + code:88C8-0FAF + cheat + description:1-ups worth nothing + code:DDCE-6F6D + cheat + description:1-ups worth 3 + code:D7CE-6F6D + cheat + description:1-ups worth 5 + code:D9CE-6F6D + cheat + description:Monster books are worth nothing + code:DDCA-AF0D + cheat + description:Monster books are worth 2 + code:D4CA-AF0D + cheat + description:Monster books are worth 10 + code:FDCA-AF0D + cheat + description:Most health power-ups worth nothing + code:DDCB-A7DD + cheat + description:Most health power-ups worth more + code:D4CB-A7DD + cheat + description:Start with 1 life + code:DFC7-17FC + cheat + description:Start with 10 lives + code:DBC7-17FC + cheat + description:Start with 50 lives + code:0BC7-17FC + cheat + description:Start with 0 special scares + code:DD69-37BF + cheat + description:Start with 10 special scares + code:FD69-37BF + cheat + description:Start with 20 special scares + code:4D69-37BF + cheat + description:Infinite health (alt) + code:7E0B7A:0D + cheat + description:Infinite lives (alt) + code:7E13C8:09 + +cartridge sha256:bb83f982961c33b81fefc1f545e18ab572d1c43cf6c241948544f05a1a71f2ba + title:ABC Monday Night Football (USA) + cheat + description:Always 1st down + code:7E119C:01 + cheat + description:1 yard to go for 1st down + code:7E119D:01 + cheat + description:Infinite time - minutes + code:7E11A6:09 + cheat + description:Infinite time - seconds + code:7E11A6:09 + cheat + description:Have 0 points - Team 1 + code:7E1182:00 + cheat + description:Have 0 points - Team 2 + code:7E118C:00 + cheat + description:Have 7 points - Team 1 + code:7E1182:07 + cheat + description:Have 7 points - Team 2 + code:7E118C:07 + cheat + description:Have 14 points - Team 1 + code:7E1182:14 + cheat + description:Have 14 points - Team 2 + code:7E118C:14 + cheat + description:Have 21 points - Team 1 + code:7E1182:21 + cheat + description:Have 21 points - Team 2 + code:7E118C:21 + cheat + description:Have 99 points - Team 1 + code:7E1182:99 + cheat + description:Have 99 points - Team 2 + code:7E118C:99 + +cartridge sha256:d07e8802a6d9c777247874e05ec08fce7e0fa1bf122cc1ab9913f7d828e4072b + title:ACME Animation Factory (USA) + cheat + description:Infinite time - game mode + code:7E1BA4:3C + +cartridge sha256:555ff99acb1b02e67ae7da12b776cdbfa9a56b8ddf248258158ec58a151554ef + title:Acrobat Mission (Japan) + cheat + description:Invincibility + code:3CC2-A766 + cheat + description:Infinite lives + code:82C2-64DB + cheat + description:Invincibility (alt) + code:7E042A:30 + cheat + description:Infinite lives (alt) + code:7E0412:04 + cheat + description:Infinite lives (alt 2) + code:7E0412:0B + cheat + description:Most Powerful gun [00-10] (don't pick any weapon icons) + code:7E0424:?? + cheat + description:Score Modifier [00-99] + code:7E02B3:??+7E02B4:?? + +cartridge sha256:41af71166f509b0e615b00e7dc3cf2dc660d1701014ecadfd1629257b18471b9 + title:Action Pachio (Japan) + cheat + description:Invincibility + code:ED60-1FC9 + cheat + description:Infinite health + code:C96B-30DD + cheat + description:Infinite time + code:C922-CFF3 + cheat + description:Infinite lives + code:C963-4D9A + cheat + description:Infinite health (alt) + code:7E00CC:0A + cheat + description:Infinite lives (alt) + code:7E00C8:09 + cheat + description:Infinite Coins + code:7E00C2:99 + cheat + description:Infinite time (alt) + code:7E00C0:63+7E00C1:63 + cheat + description:Infinite continue time + code:7E1E12:09 + cheat + description:Max score + code:7E00C4:99+7E00C5:99+7E00C6:99+7E00C7:99 + +cartridge sha256:b8055844825653210d252d29a2229f9a3e7e512004e83940620173c57d8723f0 + title:ActRaiser (USA) + cheat + description:Invincibility after one hit + code:1DBB-D4D7 + cheat + description:Infinite health in action sequences + code:2264-6FD4 + cheat + description:Infinite MP (Magic Points) + code:C9BD-6467 + cheat + description:Infinite SP (Spell Points) + code:CEA5-6DA3 + cheat + description:Infinite time + code:C98B-D468 + cheat + description:Infinite time (alt) + code:DD8B-D4D8 + cheat + description:Faster timer + code:FD86-D4A8 + cheat + description:Slower timer + code:9D86-D4A8 + cheat + description:Unlock professional mode + code:DD67-D7AD + cheat + description:Monster lairs are always empty + code:B38B-07D3 + cheat + description:Towns always able to grow + code:DD60-07A2 + cheat + description:Have Fire magic and 24 MP in professional mode + code:69C4-AF6C+62C4-A7DC+CBC4-A46C+DFC4-A4AC + cheat + description:Have Stardust and 24 MP in professional mode + code:69C4-AF6C+62C4-A7DC+CBC4-A46C+D4C4-A4AC + cheat + description:Have Aura magic and 24 MP in professional mode + code:69C4-AF6C+62C4-A7DC+CBC4-A46C+D7C4-A4AC + cheat + description:Start with 1/2 health (first game only) + code:D081-6DD8 + cheat + description:Infinite health in action sequences (alt) + code:7E001D:08 + cheat + description:Infinite health in sim mode + code:7E0286:08 + cheat + description:Infinite magic in action sequences + code:7E0021:05 + cheat + description:Infinite time (alt 2) + code:02BC98:00 + cheat + description:Have Sword Shot + code:7E00E4:80 + cheat + description:One hit kills on bosses + code:7E0BCC:00 + cheat + description:Level 99 + code:7E0291:63 + cheat + description:Have Fire magic + code:7E02AC:01 + cheat + description:Have Stardust magic + code:7E02AC:02 + cheat + description:Have Aura magic + code:7E02AC:03 + cheat + description:Have Light magic + code:7E02AC:04 + cheat + description:Slot 1 - Source of Life + code:7E02A2:05 + cheat + description:Slot 1 - Source of Magic + code:7E02A2:06 + cheat + description:Slot 1 - Loaf of Bread + code:7E02A2:07 + cheat + description:Slot 1 - Wheat + code:7E02A2:08 + cheat + description:Slot 1 - Herb + code:7E02A2:09 + cheat + description:Slot 1 - Bridge + code:7E02A2:0A + cheat + description:Slot 1 - Harmonious Music + code:7E02A2:0B + cheat + description:Slot 1 - Ancient Tablet + code:7E02A2:0C + cheat + description:Slot 1 - Magic Skull + code:7E02A2:0E + cheat + description:Slot 1 - Sheep's Fleece + code:7E02A2:0F + cheat + description:Slot 1 - Bomb + code:7E02A2:10 + cheat + description:Slot 1 - Compass + code:7E02A2:13 + cheat + description:Slot 1 - Strength of Angel + code:7E02A2:14 + cheat + description:Slot 2 - Source of Life + code:7E02A3:05 + cheat + description:Slot 2 - Source of Magic + code:7E02A3:06 + cheat + description:Slot 2 - Loaf of Bread + code:7E02A3:07 + cheat + description:Slot 2 - Wheat + code:7E02A3:08 + cheat + description:Slot 2 - Herb + code:7E02A3:09 + cheat + description:Slot 2 - Bridge + code:7E02A3:0A + cheat + description:Slot 2 - Harmonious Music + code:7E02A3:0B + cheat + description:Slot 2 - Ancient Tablet + code:7E02A3:0C + cheat + description:Slot 2 - Magic Skull + code:7E02A3:0E + cheat + description:Slot 2 - Sheep's Fleece + code:7E02A3:0F + cheat + description:Slot 2 - Bomb + code:7E02A3:10 + cheat + description:Slot 2 - Compass + code:7E02A3:13 + cheat + description:Slot 2 - Strength of Angel + code:7E02A3:14 + cheat + description:Slot 3 - Source of Life + code:7E02A4:05 + cheat + description:Slot 3 - Source of Magic + code:7E02A4:06 + cheat + description:Slot 3 - Loaf of Bread + code:7E02A4:07 + cheat + description:Slot 3 - Wheat + code:7E02A4:08 + cheat + description:Slot 3 - Herb + code:7E02A4:09 + cheat + description:Slot 3 - Bridge + code:7E02A4:0A + cheat + description:Slot 3 - Harmonious Music + code:7E02A4:0B + cheat + description:Slot 3 - Ancient Tablet + code:7E02A4:0C + cheat + description:Slot 3 - Magic Skull + code:7E02A4:0E + cheat + description:Slot 3 - Sheep's Fleece + code:7E02A4:0F + cheat + description:Slot 3 - Bomb + code:7E02A4:10 + cheat + description:Slot 3 - Compass + code:7E02A4:13 + cheat + description:Slot 3 - Strength of Angel + code:7E02A4:14 + cheat + description:Slot 4 - Source of Life + code:7E02A5:05 + cheat + description:Slot 4 - Source of Magic + code:7E02A5:06 + cheat + description:Slot 4 - Loaf of Bread + code:7E02A5:07 + cheat + description:Slot 4 - Wheat + code:7E02A5:08 + cheat + description:Slot 4 - Herb + code:7E02A5:09 + cheat + description:Slot 4 - Bridge + code:7E02A5:0A + cheat + description:Slot 4 - Harmonious Music + code:7E02A5:0B + cheat + description:Slot 4 - Ancient Tablet + code:7E02A5:0C + cheat + description:Slot 4 - Magic Skull + code:7E02A5:0E + cheat + description:Slot 4 - Sheep's Fleece + code:7E02A5:0F + cheat + description:Slot 4 - Bomb + code:7E02A5:10 + cheat + description:Slot 4 - Compass + code:7E02A5:13 + cheat + description:Slot 4 - Strength of Angel + code:7E02A5:14 + cheat + description:Slot 5 - Source of Life + code:7E02A6:05 + cheat + description:Slot 5 - Source of Magic + code:7E02A6:06 + cheat + description:Slot 5 - Loaf of Bread + code:7E02A6:07 + cheat + description:Slot 5 - Wheat + code:7E02A6:08 + cheat + description:Slot 5 - Herb + code:7E02A6:09 + cheat + description:Slot 5 - Bridge + code:7E02A6:0A + cheat + description:Slot 5 - Harmonious Music + code:7E02A6:0B + cheat + description:Slot 5 - Ancient Tablet + code:7E02A6:0C + cheat + description:Slot 5 - Magic Skull + code:7E02A6:0E + cheat + description:Slot 5 - Sheep's Fleece + code:7E02A6:0F + cheat + description:Slot 5 - Bomb + code:7E02A6:10 + cheat + description:Slot 5 - Compass + code:7E02A6:13 + cheat + description:Slot 5 - Strength of Angel + code:7E02A6:14 + cheat + description:Slot 6 - Source of Life + code:7E02A7:05 + cheat + description:Slot 6 - Source of Magic + code:7E02A7:06 + cheat + description:Slot 6 - Loaf of Bread + code:7E02A7:07 + cheat + description:Slot 6 - Wheat + code:7E02A7:08 + cheat + description:Slot 6 - Herb + code:7E02A7:09 + cheat + description:Slot 6 - Bridge + code:7E02A7:0A + cheat + description:Slot 6 - Harmonious Music + code:7E02A7:0B + cheat + description:Slot 6 - Ancient Tablet + code:7E02A7:0C + cheat + description:Slot 6 - Magic Skull + code:7E02A7:0E + cheat + description:Slot 6 - Sheep's Fleece + code:7E02A7:0F + cheat + description:Slot 6 - Bomb + code:7E02A7:10 + cheat + description:Slot 6 - Compass + code:7E02A7:13 + cheat + description:Slot 6 - Strength of Angel + code:7E02A7:14 + cheat + description:Slot 7 - Source of Life + code:7E02A8:05 + cheat + description:Slot 7 - Source of Magic + code:7E02A8:06 + cheat + description:Slot 7 - Loaf of Bread + code:7E02A8:07 + cheat + description:Slot 7 - Wheat + code:7E02A8:08 + cheat + description:Slot 7 - Herb + code:7E02A8:09 + cheat + description:Slot 7 - Bridge + code:7E02A8:0A + cheat + description:Slot 7 - Harmonious Music + code:7E02A8:0B + cheat + description:Slot 7 - Ancient Tablet + code:7E02A8:0C + cheat + description:Slot 7 - Magic Skull + code:7E02A8:0E + cheat + description:Slot 7 - Sheep's Fleece + code:7E02A8:0F + cheat + description:Slot 7 - Bomb + code:7E02A8:10 + cheat + description:Slot 7 - Compass + code:7E02A8:13 + cheat + description:Slot 7 - Strength of Angel + code:7E02A8:14 + cheat + description:Slot 8 - Source of Life + code:7E02A9:05 + cheat + description:Slot 8 - Source of Magic + code:7E02A9:06 + cheat + description:Slot 8 - Loaf of Bread + code:7E02A9:07 + cheat + description:Slot 8 - Wheat + code:7E02A9:08 + cheat + description:Slot 8 - Herb + code:7E02A9:09 + cheat + description:Slot 8 - Bridge + code:7E02A9:0A + cheat + description:Slot 8 - Harmonious Music + code:7E02A9:0B + cheat + description:Slot 8 - Ancient Tablet + code:7E02A9:0C + cheat + description:Slot 8 - Magic Skull + code:7E02A9:0E + cheat + description:Slot 8 - Sheep's Fleece + code:7E02A9:0F + cheat + description:Slot 8 - Bomb + code:7E02A9:10 + cheat + description:Slot 8 - Compass + code:7E02A9:13 + cheat + description:Slot 8 - Strength of Angel + code:7E02A9:14 + +cartridge sha256:71bdd448a30b88725864e55594ebb67a118b1f197a3f9e5dd39dbf23399efa15 + title:ActRaiser 2 (USA) + cheat + description:Infinite health from most enemies + code:C2B0-CF07 + cheat + description:Infinite health from some ground hazards + code:C2B2-C7D3 + cheat + description:Infinite time + code:DD33-476F + cheat + description:Infinite MP (must have one to cast) + code:3C65-CFA8 + cheat + description:Infinite lives + code:DD67-4468 + cheat + description:One hit kills + code:DDB3-C764 + cheat + description:Small magic power-up adds 3 instead of 1 + code:D7C0-37A7 + cheat + description:Small magic power-up adds 5 + code:D9C0-37A7 + cheat + description:Small magic power-up adds 9 + code:DBC0-37A7 + cheat + description:Large magic power-up adds 1 instead of 3 + code:DFC9-3407 + cheat + description:Large magic power-up adds 5 + code:D9C9-3407 + cheat + description:Large magic power-up adds 9 + code:DBC9-3407 + cheat + description:Small health power-ups add 1 instead of 2 + code:DFC7-3D67 + cheat + description:Small health power-ups add 4 + code:D0C7-3D67 + cheat + description:Small health power-ups add 15 + code:F9C7-3D67 + cheat + description:Small health power-ups heal completely + code:F0C7-3D67 + cheat + description:Medium health power-ups add 2 instead of 5 + code:D4C9-3FD7 + cheat + description:Medium health power-ups add 8 + code:D6C9-3FD7 + cheat + description:Medium health power-ups add 15 + code:F9C9-3FD7 + cheat + description:Medium health power-ups heal completely + code:F0C9-3FD7 + cheat + description:Large health power-ups add 2 instead of 10 + code:D4C7-3FA7 + cheat + description:Large health power-ups add 5 + code:D0C7-3FA7 + cheat + description:Large health power-ups add 15 + code:F9C7-3FA7 + cheat + description:Large health power-ups heal completely + code:F0C7-3FA7 + cheat + description:Start with 3 lives on Easy + code:D727-4DD1 + cheat + description:Start with 10 lives on Easy + code:FD27-4DD1 + cheat + description:Start with 50 lives on Easy + code:9D27-4DD1 + cheat + description:Start with 1 life on Normal + code:DF27-4D61 + cheat + description:Start with 5 lives on Normal + code:D927-4D61 + cheat + description:Start with 10 lives on Normal + code:FD27-4D61 + cheat + description:Start with 50 lives on Normal + code:9D27-4D61 + cheat + description:Start with 1 life on Hard + code:DF27-4FD1 + cheat + description:Start with 5 lives on Hard + code:D927-4FD1 + cheat + description:Start with 10 lives on Hard + code:FD27-4FD1 + cheat + description:Start with 50 lives on Hard + code:9D27-4FD1 + cheat + description:Start with 2 MP on Easy + code:D484-1F66 + cheat + description:Start with 7 MP on Easy + code:D584-1F66 + cheat + description:Start with 9 MP on Easy + code:DB84-1F66 + cheat + description:Start with 1 MP on Normal or Hard + code:DF8F-1766 + cheat + description:Start with 5 MP on Normal or Hard + code:D98F-1766 + cheat + description:Start with 7 MP on Normal or Hard + code:D58F-1766 + cheat + description:Start with 9 MP on Normal or Hard + code:DB8F-1766 + cheat + description:Start with 1/2 health + code:DC8F-1F06 + cheat + description:Start with 3/4 health + code:DE8F-1F06 + cheat + description:Invincibility (blinking) + code:7F205E:18 + cheat + description:Infinite health (alt) + code:7E091D:16 + cheat + description:Infinite time (alt) (disable at end of level) + code:7E094D:63 + +cartridge sha256:e645310d2406ace85523ed91070ee7ff6aa245217267dacb158ae9fc75109692 + title:Addams Family, The (USA) + cheat + description:Invincibility + code:2DA7-670D + cheat + description:Infinite health + code:3CA7-A467 + cheat + description:Infinite health (alt) + code:1DA7-A4A7 + cheat + description:Infinite health (alt 2) + code:C9A7-A4A7 + cheat + description:Infinite lives + code:DDA1-A4A7 + cheat + description:Infinite lives (alt) + code:C9A1-A7D7 + cheat + description:Double-jump + code:DD87-0FA7 + cheat + description:Each $ worth 5 + code:D9CF-DDAF + cheat + description:Each $ worth 10 + code:FDCF-DDAF + cheat + description:Each $ worth 25 + code:49CF-DDAF + cheat + description:Have Fezi-copter + code:6DAC-6FDD + cheat + description:Start with and keep Fezi-copter (disable after defeating a boss, land before password screen) + code:3CAD-A46D+60BA-6704 + cheat + description:Start with 1 heart + code:DF61-0F0D+DF61-0F6D + cheat + description:Start with 3 hearts + code:D761-0F0D+D761-0F6D + cheat + description:Start with 4 hearts + code:D061-0F0D+D061-0F6D + cheat + description:Start with 5 hearts + code:D961-0F0D+D961-0F6D + cheat + description:Start with 1 life + code:DFB8-6F04 + cheat + description:Start with 3 lives + code:D7B8-6F04 + cheat + description:Start with 9 lives + code:DBB8-6F04 + cheat + description:Start with 20 lives + code:4DB8-6F04 + cheat + description:Start with 50 lives + code:9DB8-6F04 + cheat + description:Start with 99 lives + code:BBB8-6F04 + cheat + description:Infinite health and max hearts + code:7E00C3:05 + cheat + description:Always throw Balls + code:7E00EF:01 + cheat + description:Have Fezi-copter (alt) + code:7E0064:FF + cheat + description:Have Foil (Sword) + code:7E00EE:01 + +cartridge sha256:b6957bae7fd97ba681afbf8962fe2138e209649fd88ed9add2d5233178680aaa + title:Addams Family, The - Pugsley's Scavenger Hunt (USA) + cheat + description:Infinite health + code:3CCC-446D + cheat + description:Infinite hearts + code:3CCC-446D + cheat + description:Infinite lives + code:DDB6-1FA7 + cheat + description:Each $ worth 5 + code:D9C9-476D + cheat + description:Each $ worth 25 + code:49C9-476D + cheat + description:Higher jump + code:3BA5-37D4+D9A5-3704 + cheat + description:Super-jump + code:3BA5-37D4+D5A5-3704 + cheat + description:Mega-jump + code:3BA5-37D4+DBA5-3704 + cheat + description:Longer invulnerability time after being hit + code:5EC8-4DDD + cheat + description:Shorter invulnerability time after being hit + code:D6C8-4DDD + cheat + description:Get 0 lives for each $100 and 1-Up + code:DDB0-C767 + cheat + description:Get 2 lives for each $100 and 1-Up + code:D4B0-C767 + cheat + description:Start with 1 heart (don't edit hearts in options menu) + code:DDED-D76D + cheat + description:Start with 2 hearts (don't edit hearts in options menu) + code:DFED-D76D + cheat + description:Start with 5 hearts (don't edit hearts in options menu) + code:D0ED-D76D + cheat + description:Start with 4 lives (don't edit lives in options menu) + code:DDED-D40D + cheat + description:Start with 16 lives (don't edit lives in options menu) + code:DBED-D40D + cheat + description:Start with 64 lives (don't edit lives in options menu) + code:7DED-D40D + cheat + description:Infinite health (alt) + code:7E0095:03 + cheat + description:Infinite lives (alt) + code:7E004D:09 + cheat + description:Infinite Cash + code:7E004E:99 + +cartridge sha256:f59a0a8ed11ea2ba6217b1640e74bab8d8d8161a4585f5ae4a02edd7958ad9a3 + title:Addams Family Values (USA) (En,Fr,De) + cheat + description:Infinite health against enemies + code:FFBD-C767 + cheat + description:Infinite health against everything + code:3C8F-C40D + cheat + description:Infinite Small Rocks + code:DD24-3D0F + cheat + description:Infinite Blue Marbles + code:DD2C-C7AF + cheat + description:Infinite Magic Seeds + code:DD22-CF0F + cheat + description:Infinite Swamp Slime + code:DD2E-C4AF + cheat + description:Infinite cookies + code:8E2A-1D6D + cheat + description:Start with full skull meter + code:FA62-3F0D + cheat + description:Start with all items + code:EE6C-320D + cheat + description:Have Amulet of True Sight + code:7EE9FC:FF + cheat + description:Have Big Book of Bisquits + code:7EE9F0:FF + cheat + description:Have Black Beetle Cookies + code:7EE9E0:FF+7EE9E4:FF + cheat + description:Have Black Egg + code:7EEA05:FF + cheat + description:Have Black Rose + code:7EE9FA:FF + cheat + description:Have Bone Spoon + code:7EE9F7:FF + cheat + description:Have Book of Flying + code:7EE9F9:FF + cheat + description:Have Candle + code:7EE9F6:FF + cheat + description:Have Clyde's Cookie Compendium + code:7EE9EF:FF + cheat + description:Have Crumble Cookies + code:7EE9E2:FF+7EE9E6:FF + cheat + description:Have Crusty Cookies + code:7EE9E1:FF+7EE9E5:FF + cheat + description:Have Dragon Belch Cookies + code:7EE9DF:FF+7EE9E3:FF + cheat + description:Have Firefly + code:7EEA03:FF + cheat + description:Have Gold Coin + code:7EEA06:FF + cheat + description:Have Green Key + code:7EE9D8:FF + cheat + description:Have Greenhouse Key + code:7EE9D7:FF + cheat + description:Have Headless Teddy + code:7EE9F4:FF + cheat + description:Have Iron Key + code:7EE9DE:FF + cheat + description:Have Jewelled Key + code:7EE9DB:FF + cheat + description:Have Journal + code:7EE9F2:FF + cheat + description:Have Large Vine + code:7EEA02:FF + cheat + description:Have Lurch's Bowling Ball + code:7EEA04:FF + cheat + description:Have Magnet + code:7EE9FF:FF + cheat + description:Have Max's Munch Manual + code:7EE9F1:FF + cheat + description:Have Money + code:7E004E:63 + cheat + description:Have Musical Box + code:7EE9FB:FF + cheat + description:Have Plant Food + code:7EE9EA:FF + cheat + description:Have Portal Potion + code:7EE9E8:FF + cheat + description:Have Pumpkin + code:7EE9F3:FF + cheat + description:Have Red Potion + code:7EE9E7:FF + cheat + description:Have Sack of Gold + code:7EE9F5:FF + cheat + description:Have Slimming Potion + code:7EE9E9:FF + cheat + description:Have Shockwave + code:7EE9FD:FF + cheat + description:Have Skull Rattle + code:7EE9F8:FF + cheat + description:Have Skull Key + code:7EE9D9:FF + cheat + description:Have Spider Key + code:7EE9DD:FF + cheat + description:Have Spider's Eye + code:7EE9FE:FF + cheat + description:Have Stone Button + code:7EEA01:FF + cheat + description:Have Stone Key + code:7EE9DC:FF + cheat + description:Have Stone Twig Key + code:7EE9DA:FF + cheat + description:Have Strange Black Cube + code:7EEA00:FF + +cartridge sha256:8083307f3f4b7df9e5bf53d5f25877c2e548f0f677540d4ee62d60ccca3098f8 + title:Adventures of Batman & Robin, The (USA) + cheat + description:Invincibility (except after being grabbed) + code:2DC7-1DAD + cheat + description:Infinite health + code:C982-4F0D + cheat + description:Infinite health (alt) + code:DD8A-4D6D + cheat + description:Get full health from hearts + code:466B-4494 + cheat + description:Infinite Stars + code:C9A1-34AF + cheat + description:Infinite Spray Gun ammo + code:C9A5-34DF + cheat + description:Infinite Plastic Explosives + code:C9AB-3D6F + cheat + description:Infinite Smoke Bombs + code:C9A6-3F0F + cheat + description:Infinite Missiles + code:DDA1-34AF + cheat + description:Infinite Bombs + code:DDAB-3D6F + cheat + description:Infinite lives + code:C988-340D + cheat + description:Moon-jump + code:4DAF-14DF + cheat + description:Super-jump + code:E6C7-34DF + cheat + description:Move slower + code:DD8D-C765+EE8F-CDD5 + cheat + description:Move faster + code:D08D-C765+E88F-CDD5 + cheat + description:Move even faster + code:D58D-C765+E68F-CDD5 + cheat + description:Moon-walk + code:E38D-C765+DF8F-CDD5 + cheat + description:Moon-walk faster + code:E88D-C765+D08F-CDD5 + cheat + description:Moon-walk even faster + code:E68D-C765+E58F-CDD5 + cheat + description:No credits + code:DD86-4D19 + cheat + description:Don't start with any Explosives and Smoke Bomb ammo + code:DDBE-3F0F + cheat + description:Don't start with any Stars and Spray Gun ammo + code:DDB3-376F + cheat + description:Start with 25 Stars and Spray Gun ammo + code:FBB3-376F + cheat + description:Start with 50 Stars and Spray Gun ammo + code:77B3-376F + cheat + description:Start with 25 Explosives and Smoke Bomb ammo + code:FBBE-3F0F + cheat + description:Start with 50 Explosives and Smoke Bomb ammo + code:77BE-3F0F + cheat + description:Start with 9 lives - not on easy mode + code:DB86-4FC9 + cheat + description:Start with 6 lives - not on easy mode + code:D186-4FC9 + cheat + description:Start with 1 life - not on easy mode + code:DD86-4FC9 + cheat + description:Start with 9 credits + code:DB86-4D19 + cheat + description:Start with 6 credits + code:D186-4D19 + cheat + description:Infinite health (alt 2) + code:7E0098:28 + cheat + description:Infinite item #3 + code:7E00A0:09 + cheat + description:Infinite item #4 + code:7E00A2:09 + cheat + description:Infinite item #5 + code:7E00A4:09 + cheat + description:Infinite item #6 + code:7E00A6:09 + +cartridge sha256:ecd964ae44e61203bc8759cfc6441365bf0c6e7bae6ad2a0fd553d4c7efab71e + title:Adventures of Dr. Franken, The (USA) + cheat + description:Invincibility + code:3CBB-CDD7 + cheat + description:Health power-ups give a full health bar + code:D3A0-1404+62A5-1464 + cheat + description:Infinite health (glitchy) + code:C2BB-4F0F+C2BB-44DF + cheat + description:Infinite time + code:C220-C7A4 + cheat + description:Infinite lives + code:C2B9-C4AD + cheat + description:Infinite Power Balls + code:3CB5-14AF + cheat + description:Infinite Freeze + code:3CBB-1F0F + cheat + description:Infinite Fire + code:3CBB-1D0F + cheat + description:Infinite Lightning + code:3CB5-1FAF + +cartridge sha256:670d898bdcf97d7ca3aab6c2dd1641f1270fcc2a070bbd3028ab413aef2b2ecc + title:Adventures of Kid Kleets, The (USA) (En,Fr,Es) + cheat + description:Invincibility + code:1DA6-14A0 + cheat + description:Infinite time + code:C26A-3709 + cheat + description:Infinite health + code:C2A6-1700 + cheat + description:Infinite lives + code:C282-34A1 + +cartridge sha256:b70099186d3774355ac5db370240e370c73f9ce5341f6c805cf9f771374b43ae + title:Adventures of Rocky and Bullwinkle and Friends, The (USA) + cheat + description:Invincibility + code:2DCA-19E4+EDCA-1554 + cheat + description:Infinite chances + code:C28C-1F44 + cheat + description:Infinite lives + code:C2CE-CF61 + cheat + description:Infinite ammo + code:C2CF-CF01 + cheat + description:Infinite health + code:C2CF-308D + cheat + description:Infinite continues + code:C2E3-47C6 + cheat + description:Don't lose ammo when you die + code:C2C9-35ED + cheat + description:Don't lose collected flags when you die + code:C2C7-C18D + cheat + description:1-Up with every flag collected + code:DFCA-1761 + +cartridge sha256:8049175767eddbc3e21ca5b94ee23fc225f834ccfab4ded30d2e981b0ef73ab6 + title:Adventures of Yogi Bear (USA) + cheat + description:Infinite health + code:C2CD-1404 + cheat + description:Infinite lives + code:C269-47DD + +cartridge sha256:b737de81315eef8ded7cfd5df6b37aba01d9e6e14566486db7ec83eb0c1aa85e + title:Aero Fighters (USA) + cheat + description:Invincibility + code:82C2-4D64 + cheat + description:Infinite lives - both players + code:8229-37A0 + cheat + description:Don't lose power-ups when you die - both players + code:8229-37D0 + cheat + description:Infinite Bombs for American F-18 - P1 + code:8237-47A1 + cheat + description:Infinite Bombs for Japanese FSX - P1 + code:8237-47A9 + cheat + description:Infinite Bombs for Swedish AJ-37 - P1 + code:8237-1D09 + cheat + description:Infinite Bombs for British AV-8 - P1 + code:8237-17A9 + cheat + description:Infinite Bombs for American F-15 - P2 + code:823E-3D60 + cheat + description:Infinite Bombs for Japanese F-15 - P2 + code:823A-4D09 + cheat + description:Infinite Bombs for Swedish JAS-39 - P2 + code:8239-1FD9 + cheat + description:Infinite Bombs for British IDS - P2 + code:823D-C769 + cheat + description:Infinite lives (alt) + code:7FB78C:02 + cheat + description:Max Cannon power + code:7FB794:03 + cheat + description:Infinite Bombs / Specials + code:7FB790:02 + +cartridge sha256:18a553dafd4980cc2869180b05f9fdf6e980bf092cc683e498ec6373c9701c6e + title:Aero the Acro-Bat (USA) + cheat + description:Infinite health from most enemies + code:3CED-3DDC + cheat + description:Start with more health + code:1A27-4D03 + cheat + description:Infinite time + code:DDEC-146A + cheat + description:Infinite lives + code:DD6B-37AF + cheat + description:Start with 19 lives + code:5D68-4FDD + cheat + description:Infinite continues + code:C26E-3724 + cheat + description:Each star platform is worth 4 + code:D034-C7AD + +cartridge sha256:fc5df5db0a96d39d3df651f63993adf0f5cb5a6b92a36211f3a05d460d92c72d + title:Aero the Acro-Bat 2 (USA) + cheat + description:Invincibility + code:2DB0-4D6D + cheat + description:Infinite health + code:A287-CFAE + cheat + description:Almost infinite health + code:C287-CFAE + cheat + description:Infinite lives + code:C26C-4D0F + cheat + description:Infinite Stars + code:C227-4DDE + cheat + description:Infinite Shots + code:DD24-476E + cheat + description:Stars worth 3 + code:D7C8-17D3 + cheat + description:Stars worth 5 + code:D9C8-17D3 + cheat + description:Stars worth 7 + code:D5C8-17D3 + cheat + description:Double Drill icon lasts 99 seconds + code:BBC2-C463 + cheat + description:Double Drill icon lets you drill 4 times instead of 2 + code:D0C2-CD03 + cheat + description:Double Drill icon lets you drill 9 times instead of 2 + code:DBC2-CD03 + cheat + description:Can drill 5 times in the air until you pick-up a drill icon + code:D936-4DF1 + cheat + description:Can drill 9 times in the air until you pick-up a drill icon + code:DB36-4DF1 + cheat + description:Drill as many times as you want without hitting the ground + code:C26E-4F03 + cheat + description:Move faster + code:D468-CDAA+E26A-CD0A + cheat + description:Move even faster + code:D768-CDAA+EA6A-CD0A + cheat + description:Jump higher + code:FD67-3DD2 + cheat + description:Super-jump when standing still + code:E66E-4F62+E661-C762 + cheat + description:Flying icon worth 99 seconds of flight time + code:BBC3-3D63 + cheat + description:Start each life with max health + code:D939-14F1 + +cartridge sha256:d5f0fbeed3774bbccbd769698fc4051487a0a5eb699790a8a094451595600f60 + title:Aerobiz (USA) + cheat + description:In scenario 1, Tokyo starts with $649,280,000 + code:DDA6-0DFD + cheat + description:In scenario 1, Tokyo starts with $7,202,880,000 + code:D9A6-0DFD + cheat + description:In scenario 1, Beijing starts with $420,160,000 + code:94A6-0D2D + cheat + description:In scenario 1, Beijing starts with $7,393,600,000 + code:D9A6-0FFD + cheat + description:In scenario 1, Hong Kong starts with $449,440,000 + code:95A6-0F2D + cheat + description:In scenario 1, Hong Kong starts with $7,453,600,000 + code:D9A6-04FD + cheat + description:In scenario 1, Singapore starts with $400,640,000 + code:03A6-042D + cheat + description:In scenario 1, Singapore starts with $7,353,600,000 + code:D9A6-07FD + cheat + description:In scenario 1, Sydney starts with $297,920,000 + code:7CA6-072D + cheat + description:In scenario 1, Sydney starts with $7,153,600,000 + code:D9AB-0DFD + cheat + description:In scenario 1, Delhi starts with $317,440,000 + code:73AB-0D2D + cheat + description:In scenario 1, Delhi starts with $7,193,600,000 + code:D9AB-0FFD + cheat + description:In scenario 1, Tehran starts with $239,360,000 + code:43AB-0F2D + cheat + description:In scenario 1, Tehran starts with $7,033,600,000 + code:D9AB-04FD + cheat + description:In scenario 1, Cairo starts with $249,120,000 + code:7DAB-042D + cheat + description:In scenario 1, Cairo starts with $7,053,600,000 + code:D9AB-07FD + cheat + description:In scenario 1, Nairobi starts with $200,320,000 + code:45AB-072D + cheat + description:In scenario 1, Nairobi starts with $6,953,600,000 + code:D9AC-0DFD + cheat + description:In scenario 1, Lagos starts with $229,600,000 + code:4AAC-0D2D + cheat + description:In scenario 1, Lagos starts with $7,013,600,000 + code:D9AC-0FFD + cheat + description:In scenario 1, Moscow starts with $289,280,000 + code:DDAC-04FD + cheat + description:In scenario 1, Moscow starts with $6,842,880,000 + code:D9AC-04FD + cheat + description:In scenario 1, London starts with $949,280,000 + code:DDAC-07FD + cheat + description:In scenario 1, London starts with $7,502,880,000 + code:D9AC-07FD + cheat + description:In scenario 1, Paris starts with $289,280,000 + code:DDA8-0DFD + cheat + description:In scenario 1, Paris starts with $6,842,880,000 + code:D9A8-0DFD + cheat + description:In scenario 1, Rome starts with $371,360,000 + code:06A8-0D2D + cheat + description:In scenario 1, Rome starts with $7,293,600,000 + code:D9A8-0FFD + cheat + description:In scenario 1, New York starts with $189,280,000 + code:DDA8-04FD + cheat + description:In scenario 1, New York starts with $6,742,880,000 + code:D9A8-04FD + cheat + description:In scenario 1, Vancouver starts with $258,880,000 + code:74A8-042D + cheat + description:In scenario 1, Vancouver starts with $7,073,600,000 + code:D9A8-07FD + cheat + description:In scenario 1, Los Angeles starts with $649,280,000 + code:DDAA-0DFD + cheat + description:In scenario 1, Los Angeles starts with $7,202,880,000 + code:D9AA-0DFD + cheat + description:In scenario 1, Honolulu starts with $268,640,000 + code:70AA-0D2D + cheat + description:In scenario 1, Honolulu starts with $7,093,600,000 + code:D9AA-0FFD + cheat + description:In scenario 1, Mexico City starts with $258,880,000 + code:74AA-0F2D + cheat + description:In scenario 1, Mexico City starts with $7,073,600,000 + code:D9AA-04FD + cheat + description:In scenario 1, Lima starts with $180,800,000 + code:47AA-042D + cheat + description:In scenario 1, Lima starts with $6,913,600,000 + code:D9AA-07FD + cheat + description:In scenario 1, Rio de Janeiro starts with $317,440,000 + code:73AA-072D + cheat + description:In scenario 1, Rio de Janeiro starts with $7,193,600,000 + code:D9A2-0DFD + cheat + description:In scenario 1, Buenos Aires starts with $210,080,000 + code:4BA2-0D2D + cheat + description:In scenario 1, Buenos Aires starts with $6,973,600,000 + code:D9A2-0FFD + cheat + description:In scenario 2, Tokyo starts with $1,149,280,000 + code:DDA2-04FD + cheat + description:In scenario 2, Tokyo starts with $7,702,880,000 + code:D9A2-04FD + cheat + description:In scenario 2, Beijing starts with $498,240,000 + code:1FA2-042D + cheat + description:In scenario 2, Beijing starts with $7,553,600,000 + code:D9A2-07FD + cheat + description:In scenario 2, Hong Kong starts with $649,760,000 + code:53A2-072D + cheat + description:In scenario 2, Hong Kong starts with $7,853,600,000 + code:D9A3-0DFD + cheat + description:In scenario 2, Singapore starts with $552,160,000 + code:18A3-0D2D + cheat + description:In scenario 2, Singapore starts with $7,653,600,000 + code:D9A3-0FFD + cheat + description:In scenario 2, Sydney starts with $581,440,000 + code:5FA3-0F2D + cheat + description:In scenario 2, Sydney starts with $7,713,600,000 + code:D9A3-04FD + cheat + description:In scenario 2, Delhi starts with $517,760,000 + code:19A3-042D + cheat + description:In scenario 2, Delhi starts with $7,593,600,000 + code:D9A3-07FD + cheat + description:In scenario 2, Tehran starts with $297,920,000 + code:7CA3-072D + cheat + description:In scenario 2, Tehran starts with $7,153,600,000 + code:D9AE-0DFD + cheat + description:In scenario 2, Cairo starts with $390,880,000 + code:0AAE-0D2D + cheat + description:In scenario 2, Cairo starts with $7,333,600,000 + code:D9AE-0FFD + cheat + description:In scenario 2, Nairobi starts with $249,120,000 + code:7DAE-0F2D + cheat + description:In scenario 2, Nairobi starts with $7,053,600,000 + code:D9AE-04FD + cheat + description:In scenario 2, Lagos starts with $299,040,000 + code:7CAE-042D + cheat + description:In scenario 2, Lagos starts with $7,149,600,000 + code:D9AE-07FD + cheat + description:In scenario 2, Moscow starts with $689,280,000 + code:DDAD-6DFD + cheat + description:In scenario 2, Moscow starts with $7,242,880,000 + code:D9AD-6DFD + cheat + description:In scenario 2, London starts with $38,560,000 + code:DDAD-6FFD + cheat + description:In scenario 2, London starts with $6,592,160,000 + code:D9AD-6FFD + cheat + description:In scenario 2, Paris starts with $909,280,000 + code:DDAD-64FD + cheat + description:In scenario 2, Paris starts with $7,462,880,000 + code:D9AD-64FD + cheat + description:In scenario 2, Rome starts with $571,680,000 + code:1EAD-642D + cheat + description:In scenario 2, Rome starts with $7,693,600,000 + code:D9AD-67FD + cheat + description:In scenario 2, New York starts with $829,280,000 + code:DDAF-6DFD + cheat + description:In scenario 2, New York starts with $7,382,880,000 + code:D9AF-6DFD + cheat + description:In scenario 2, Vancouver starts with $420,160,000 + code:94AF-6D2D + cheat + description:In scenario 2, Vancouver starts with $7,393,600,000 + code:D9AF-6FFD + cheat + description:In scenario 2, Los Angeles starts with $1,109,280,000 + code:DDAF-64FD + cheat + description:In scenario 2, Los Angeles starts with $7,662,880,000 + code:D9AF-64FD + cheat + description:In scenario 2, Honolulu starts with $381,120,000 + code:0CAF-642D + cheat + description:In scenario 2, Honolulu starts with $7,313,600,000 + code:D9AF-67FD + cheat + description:In scenario 2, Mexico City starts with $468,960,000 + code:98AF-672D + cheat + description:In scenario 2, Mexico City starts with $7,493,600,000 + code:D9A4-6DFD + cheat + description:In scenario 2, Lima starts with $258,880,000 + code:74A4-6D2D + cheat + description:In scenario 2, Lima starts with $7,073,600,000 + code:D9A4-6FFD + cheat + description:In scenario 2, Rio de Janeiro starts with $630,240,000 + code:58A4-6F2D + cheat + description:In scenario 2, Rio de Janeiro starts with $7,813,600,000 + code:D9A4-64FD + cheat + description:In scenario 2, Buenos Aires starts with $361,600,000 + code:01A4-642D + cheat + description:In scenario 2, Buenos Aires starts with $7,273,600,000 + code:D9A4-67FD + cheat + description:Key Code + code:BDE3-D463 + cheat + description:Set money to less than $655,350,000 (must have Key) - P1, saved game 1 + code:DDDF-FEDD + cheat + description:Set money to over $327,680,000 (must have Key) - P1, saved game 1 + code:D9DF-FEDD + cheat + description:Set money to over $5,242,880,000 (must have Key) - P1, saved game 1 + code:D6DF-FEDD + cheat + description:Set money to over $10,485,760,000 (must have Key) - P1, saved game 1 + code:FDDF-FEDD + cheat + description:Set money to over $20,971,520,000 (must have Key) - P1, saved game 1 + code:4DDF-FEDD + cheat + description:Set money to over $41,943,040,000 (must have Key) - P1, saved game 1 + code:0DDF-FEDD + cheat + description:Set money to less than $655,350,000 (must have Key) - P2, saved game 1 + code:DDD9-FEDD + cheat + description:Set money to over $327,680,000 (must have Key) - P2, saved game 1 + code:D9D9-FEDD + cheat + description:Set money to over $5,242,880,000 (must have Key) - P2, saved game 1 + code:D6D9-FEDD + cheat + description:Set money to over $10,485,760,000 (must have Key) - P2, saved game 1 + code:FDD9-FEDD + cheat + description:Set money to over $20,971,520,000 (must have Key) - P2, saved game 1 + code:4DD9-FEDD + cheat + description:Set money to over $41,943,040,000 (must have Key) - P2, saved game 1 + code:0DD9-FEDD + cheat + description:Set money to less than $655,350,000 (must have Key) - P3, saved game 1 + code:DDDB-FEDD + cheat + description:Set money to over $327,680,000 (must have Key) - P3, saved game 1 + code:D9DB-FEDD + cheat + description:Set money to over $5,242,880,000 (must have Key) - P3, saved game 1 + code:D6DB-FEDD + cheat + description:Set money to over $10,485,760,000 (must have Key) - P3, saved game 1 + code:FDDB-FEDD + cheat + description:Set money to over $20,971,520,000 (must have Key) - P3, saved game 1 + code:4DDB-FEDD + cheat + description:Set money to over $41,943,040,000 (must have Key) - P3, saved game 1 + code:0DDB-FEDD + cheat + description:Set money to less than $655,350,000 (must have Key) - P4, saved game 1 + code:DDD2-FEDD + cheat + description:Set money to over $327,680,000 (must have Key) - P4, saved game 1 + code:D9D2-FEDD + cheat + description:Set money to over $5,242,880,000 (must have Key) - P4, saved game 1 + code:D6D2-FEDD + cheat + description:Set money to over $10,485,760,000 (must have Key) - P4, saved game 1 + code:FDD2-FEDD + cheat + description:Set money to over $20,971,520,000 (must have Key) - P4, saved game 1 + code:4DD2-FEDD + cheat + description:Set money to over $41,943,040,000 (must have Key) - P4, saved game 1 + code:0DD2-FEDD + cheat + description:Set money to less than $655,350,000 (must have Key) - P1, saved game 2 + code:DDFF-FEDD + cheat + description:Set money to over $327,680,000 (must have Key) - P1, saved game 2 + code:D9FF-FEDD + cheat + description:Set money to over $5,242,880,000 (must have Key) - P1, saved game 2 + code:D6FF-FEDD + cheat + description:Set money to over $10,485,760,000 (must have Key) - P1, saved game 2 + code:FDFF-FEDD + cheat + description:Set money to over $20,971,520,000 (must have Key) - P1, saved game 2 + code:4DFF-FEDD + cheat + description:Set money to over $41,943,040,000 (must have Key) - P1, saved game 2 + code:0DFF-FEDD + cheat + description:Set money to less than $655,350,000 (must have Key) - P2, saved game 2 + code:DDF9-FEDD + cheat + description:Set money to over $327,680,000 (must have Key) - P2, saved game 2 + code:D9F9-FEDD + cheat + description:Set money to over $5,242,880,000 (must have Key) - P2, saved game 2 + code:D6F9-FEDD + cheat + description:Set money to over $10,485,760,000 (must have Key) - P2, saved game 2 + code:FDF9-FEDD + cheat + description:Set money to over $20,971,520,000 (must have Key) - P2, saved game 2 + code:4DF9-FEDD + cheat + description:Set money to over $41,943,040,000 (must have Key) - P2, saved game 2 + code:0DF9-FEDD + cheat + description:Set money to less than $655,350,000 (must have Key) - P3, saved game 2 + code:DDFB-FEDD + cheat + description:Set money to over $327,680,000 (must have Key) - P3, saved game 2 + code:D9FB-FEDD + cheat + description:Set money to over $5,242,880,000 (must have Key) - P3, saved game 2 + code:D6FB-FEDD + cheat + description:Set money to over $10,485,760,000 (must have Key) - P3, saved game 2 + code:FDFB-FEDD + cheat + description:Set money to over $20,971,520,000 (must have Key) - P3, saved game 2 + code:4DFB-FEDD + cheat + description:Set money to over $41,943,040,000 (must have Key) - P3, saved game 2 + code:0DFB-FEDD + cheat + description:Set money to less than $655,350,000 (must have Key) - P4, saved game 2 + code:DDF2-FEDD + cheat + description:Set money to over $327,680,000 (must have Key) - P4, saved game 2 + code:D9F2-FEDD + cheat + description:Set money to over $5,242,880,000 (must have Key) - P4, saved game 2 + code:D6F2-FEDD + cheat + description:Set money to over $10,485,760,000 (must have Key) - P4, saved game 2 + code:FDF2-FEDD + cheat + description:Set money to over $20,971,520,000 (must have Key) - P4, saved game 2 + code:4DF2-FEDD + cheat + description:Set money to over $41,943,040,000 (must have Key) - P4, saved game 2 + code:0DF2-FEDD + +cartridge sha256:1f5738552c51de25ffe8aa44ff396c1ab238435296f1e8f99f8cf335483c03d5 + title:Air Cavalry (USA) + cheat + description:Infinite lives + code:3DE8-AD64 + cheat + description:Infinite 7.62mm rounds + code:82B7-D7A7 + cheat + description:Infinite 2.75 rockets + code:89E1-D7D4+89E6-DDD4+82B5-DF07 + +cartridge sha256:aa768b8b00123717c8d49f2c6731cdbfd80ab6a54128bae7594e93f45e38a19e + title:Aladdin (USA) + cheat + description:Invincibility + code:2D3A-4D01 + cheat + description:Almost invincible + code:C267-4D0A + cheat + description:Infinite health + code:A267-4D0A + cheat + description:Infinite lives + code:A221-4FA5+C221-4FA5 + cheat + description:Infinite Apples + code:C2A9-C7D5+3CA9-C4A5 + cheat + description:Infinite continues + code:C283-37DD + cheat + description:Level select on main menu + code:DDB5-3467+DDBA-3FA7 + cheat + description:Emeralds worth 2 instead of 1 + code:FA80-44AE + cheat + description:Emeralds worth 3 + code:FB80-44AE + cheat + description:Rubies worth 1 instead of 3 + code:A381-4F0E + cheat + description:Rubies worth 2 + code:C281-4F0E + cheat + description:Bonus round played after every level + code:DDA7-4DD5 + cheat + description:Only 10 gems needed for health increase/free life + code:FD86-4F6E + cheat + description:Only 20 gems needed for health increase/free life + code:4D86-4F6E + cheat + description:Only 30 gems needed for health increase/free life + code:7D86-4F6E + cheat + description:Only 40 gems needed for health increase/free life + code:0D86-4F6E + cheat + description:Only 50 gems needed for health increase/free life + code:9D86-4F6E + cheat + description:Only 60 gems needed for health increase/free life + code:1D86-4F6E + cheat + description:Only 90 gems needed for health increase/free life + code:BD86-4F6E + cheat + description:Apple power-ups worth 20 instead of 10 + code:4D8B-4DD3 + cheat + description:Apple power-ups worth 50 + code:9D8B-4DD3 + cheat + description:Apple power-ups worth 90 + code:BD8B-4DD3 + cheat + description:Start with 5 Apples + code:D967-1F60 + cheat + description:Start with 20 Apples + code:4D67-1F60 + cheat + description:Start with 2 health + code:D464-14A0 + cheat + description:Start with 5 health + code:D964-14A0 + cheat + description:Start with 7 health + code:D564-14A0 + cheat + description:Start with 1 life + code:DF64-1DD0 + cheat + description:Start with 5 lives + code:D964-1DD0 + cheat + description:Start with 20 lives + code:F064-1DD0 + cheat + description:Start with 1 continue + code:DFB8-3F07 + cheat + description:Start with 5 continues + code:D9B8-3F07 + cheat + description:Start with 9 continues + code:DCB8-3F07 + cheat + description:Invincibility (alt) + code:7E0347:04 + cheat + description:Infinite Apples (alt) + code:7E0369:99 + cheat + description:Moon-jump + code:7E08FB:16 + +cartridge sha256:e637b8241d55ee334a3452888df5e30d72c520dbb55c498db1a984438bab3e55 + title:Alien 3 (USA) + cheat + description:Invincibility + code:DD69-1FD0 + cheat + description:Infinite energy + code:6D64-1D60 + cheat + description:Take less damage + code:D464-1D60 + cheat + description:Most attacks do no damage + code:DD64-1D60 + cheat + description:Longer invulnerability after being hit + code:EE6B-CD00 + cheat + description:Slower fuel consumption for flame thrower + code:EE26-37D4 + cheat + description:Faster fuel consumption for flame thrower + code:7D26-37D4 + cheat + description:Infinite oil for flame thrower + code:3C25-3704 + cheat + description:Infinite flame thrower + code:C22A-17D1 + cheat + description:Infinite machine-gun + code:8B28-4404 + cheat + description:Infinite missiles + code:8B22-3DA4 + cheat + description:Infinite ammo for pulse rifle + code:3C28-44D4 + cheat + description:Infinite ammo for grenade launcher + code:3C22-3D64 + cheat + description:Less ammo in rifle clips (works with extra clips only, not the ones you start with) + code:742A-44A4 + cheat + description:More ammo in rifle clips (works with extra clips only, not the ones you start with) + code:CD2A-44A4 + cheat + description:Less ammo in grenade clips (works with extra clips only, not the ones you start with) + code:D923-3D64 + cheat + description:More ammo in grenade clips (works with extra clips only, not the ones you start with) + code:F023-3D64 + cheat + description:Maximum energy from medi-kits + code:DD6D-1700 + cheat + description:Less energy from medi-kits + code:D76D-1DA0 + cheat + description:Start with more rifle clips + code:FD36-44D1 + cheat + description:Start with even more rifle clips + code:4D36-44D1 + cheat + description:Start with fewer rifle clips + code:D036-44D1 + cheat + description:Start with more grenade clips + code:FD3B-4F01 + cheat + description:Start with even more grenade clips + code:4D3B-4F01 + cheat + description:Start with fewer grenade clips + code:D03B-4F01 + cheat + description:Mission 1 completed + code:7E0FDE:FF + cheat + description:Mission 2 completed + code:7E0FF0:FF + cheat + description:Mission 3 completed + code:7E0FF2:FF + cheat + description:Mission 4 completed + code:7E0FF4:FF + cheat + description:Mission 5 completed + code:7E0FF6:FF + cheat + description:Mission 6 completed + code:7E0FF8:FF + cheat + description:Mission 7 completed + code:7E0FFA:FF + cheat + description:Mission 8 completed + code:7E0FFC:FF + +cartridge sha256:05eb897d7696555790591c431c9d55a43ff9a1c12162443c17c5fcddfa5eb3c5 + title:Alien vs. Predator (USA) + cheat + description:Invincibility + code:1D3B-0FAD+6D22-D4D7 + cheat + description:Infinite health + code:C238-0FDD+C236-0DDD + cheat + description:No damage taken from punches + code:C236-0DDD + cheat + description:No damage taken from jumping attacks, tail attacks, rushes + code:C238-0FDD + cheat + description:Infinite lives + code:C286-A70D + cheat + description:Infinite lives (alt) + code:DD86-A70D + cheat + description:Infinite continues + code:3CEA-67D8 + cheat + description:One hit kills + code:6D2D-AFA7+6D37-64DD+6DB8-A765+6D39-DD6F + cheat + description:Hit anywhere + code:402B-6FD7+D12B-0D07+D12D-0D67+D13A-A4DD + cheat + description:Disc power-ups give 1 disc instead of 6 (handicap) + code:DF83-64AF + cheat + description:Disc power-ups give 3 discs + code:D783-64AF + cheat + description:Disc power-ups give 10 discs + code:DC83-64AF + cheat + description:Disc power-ups give 25 discs + code:FB83-64AF + cheat + description:Spear power-ups give 1 spear instead of 6 + code:DF8E-6D6F + cheat + description:Spear power-ups give 3 spears + code:D78E-6D6F + cheat + description:Spear power-ups give 10 spears + code:DC8E-6D6F + cheat + description:Spear power-ups give 25 spears + code:FB8E-6D6F + cheat + description:Spear and disc power-ups last until end of level (can't pick up other power-ups) + code:EDCA-0DD4 + cheat + description:Rhynth meat doesn't add to your maximum health + code:C282-6FDF + cheat + description:Rhynth meat adds 1/2 as much to maximum health (handicap) + code:D08A-6F6F + cheat + description:Rhynth meat adds 2x as much to maximum health + code:FD8A-6F6F + cheat + description:Rhynth meat adds 4x as much to maximum health + code:4D8A-6F6F + cheat + description:Rhynth meat adds nothing to your current health + code:DD82-67DF + cheat + description:Rhynth meat adds half as much to current health + code:D082-67DF + cheat + description:Rhynth meat adds 2x as much to current health + code:FD82-67DF + cheat + description:Rhynth meat adds 4x as much to current health + code:4D82-67DF + cheat + description:Ptera meat doesn't heal + code:C28D-A40F + cheat + description:Blue bottles don't heal at all + code:1D8D-A7AF + cheat + description:Blue bottles heal 1/2 of your health instead of 1/4 + code:3C8F-A76F + cheat + description:Blue bottles heal completely + code:DD84-A4DF + cheat + description:Light laser can be fired instantly + code:DFB1-A4D7 + cheat + description:Medium laser is fired above 3rd line instead of 2nd + code:F6B1-A707 + cheat + description:Medium laser can be fired above 1st line + code:D9B5-ADD7 + cheat + description:Medium laser can be fired below 1st line - eliminates light laser + code:DCB1-A4A7 + cheat + description:No damage is taken from using heavy laser + code:F6B5-AF07 + cheat + description:Heavy laser can be fired above 2nd line - eliminates medium laser + code:DFB5-AD67 + cheat + description:Start with full health bar on Standard level + code:EEB5-6404+EEB5-64A4 + cheat + description:Start with full health bar on Novice level + code:EEB5-6704+EEB5-67A4 + cheat + description:Start with full health bar on Advanced level + code:EEB6-6D04+EEB6-6DA4 + cheat + description:Start with full health bar on Expert level + code:EEB6-6F04+EEB6-6FA4 + cheat + description:Start with up to 9 lives on Options screen (selecting downward from 1 goes to 6) + code:DB8F-AD9D + cheat + description:Start with up to 30 continues on Options screen (selecting downward from 0 goes to 3) + code:F38F-AD2D + cheat + description:Start on level 1-2 + code:D4EE-A766 + cheat + description:Start on level 2-1 + code:D7EE-A766 + cheat + description:Start on level 3-1 + code:D0EE-A766 + cheat + description:Start on level 4-1 + code:D9EE-A766 + cheat + description:Start on level 5-1 + code:D1EE-A766 + cheat + description:Start on level 5-2 + code:D5EE-A766 + cheat + description:Start on level 5-3 + code:D6EE-A766 + cheat + description:Start on level 6-1 + code:DBEE-A766 + cheat + description:Start on level 6-2 + code:DCEE-A766 + cheat + description:Infinite health (alt) + code:7E1024:64 + +cartridge sha256:5c4e283efc338958b8dd45ebd6daf133a9eb280420a98e2e1df358ae0242c366 + title:Amazing Spider-Man, The - Lethal Foes (Japan) + cheat + description:Infinite health + code:7E0E0C:40 + cheat + description:Infinite lives + code:7E1C23:09 + cheat + description:Infinite time + code:7E1C22:63 + +cartridge sha256:dc9cefb4dd50dce2e9d626ac71d4a06306516cba4bc784c90e4a30fe4e7ff4ef + title:American Gladiators (USA) + cheat + description:Infinite time + code:7E00B2:59 + cheat + description:Always have 9 points - P1 + code:7E0306:09 + cheat + description:Always have 9 points in ball game - P1 + code:7E0304:09 + +cartridge sha256:6931a3eacb7ab3c2f2fb57ba7d59c6da56fe6c7d60484cebec9332e6caca3ae9 + title:American Tail, An - Fievel Goes West (USA) + cheat + description:Invincibility + code:2D6D-D4EF + cheat + description:Invincibility (alt) + code:CB6D-D47F + cheat + description:Infinite health + code:2D60-DD8F + cheat + description:Infinite lives + code:C2C5-6FDF + cheat + description:Infinite time + code:3CC4-A4DF + cheat + description:Walk left faster + code:E867-AF5D + cheat + description:Walk right faster + code:D06E-6DED + cheat + description:Multi-jumps + code:DD65-0D84 + +cartridge sha256:626f1fe52b0df0f8ede23f0062cd842321c8dabf14aefdca12e526876ecf383a + title:Animaniacs (USA) + cheat + description:Every coin gives 999 saved slot rotations + code:DFC8-3D0C + cheat + description:Every second coin gives 99 continues + code:D4CE-37AC + cheat + description:Every slot machine roll gives 99 continues + code:D9CE-37AC + cheat + description:Super-jump and float + code:CBBF-47DA+D6BF-470A+DFBF-476A + cheat + description:Invincibility + code:0CFCC0:90 + cheat + description:99 Coins + code:7F0016:63 + cheat + description:Every coin gives 999 saved slot rotations (alt) + code:82ABB1:01 + cheat + description:Every second coin gives 99 continues (alt) + code:82ABFF:02 + cheat + description:Every slot machine roll gives 99 continues (alt) + code:82ABFF:05 + cheat + description:Hold up or down against some walls to climb them + code:8390D1:FF + cheat + description:Higher jump + code:839011:FF + cheat + description:Super jump and float (alt) + code:83901C:A9+83901D:08+83901E:01 + cheat + description:Moon-jump (enable to rise slowly, disable to fall back down) + code:7E0415:FF + +cartridge sha256:31569bef662bc438194726967970bf19f504101060763cbd649350362fb6ef2f + title:Arcade's Greatest Hits - The Atari Collection 1 (USA) + cheat + description:Asteroids - Invincibility + code:1D63-34AE + cheat + description:Asteroids - Infinite lives - both players + code:896E-3D6E + cheat + description:Battlezone - Invincibility + code:ADB3-4FF9+DDB3-4F99+2DB3-4FB9+1DBF-4D95 + cheat + description:Battlezone - Infinite lives + code:C9BE-47B9 + cheat + description:Centipede - Infinite lives - both players + code:8262-C7DB + cheat + description:Super Breakout - Infinite serves - both players + code:C2AB-CDD1 + cheat + description:Tempest - Infinite lives - both players + code:82A6-C49B + +cartridge sha256:aac9d6f2b8408e4bbdc83ebbba755428caf8021fefbfac7220fb4c772abd9944 + title:Arcana (USA) + cheat + description:Infinite money for weapons + code:C225-0F02 + cheat + description:Infinite money for items + code:C22A-0402 + cheat + description:Infinite money for rooms + code:C229-640E + cheat + description:Infinite money for elixir + code:C22F-A7DE + cheat + description:Level and statistics for all characters in group are increased after each battle + code:B387-DFF2 + cheat + description:Magic points don't decrease + code:828B-AF2E + cheat + description:Start with 60,000 gold pieces + code:1D69-AFD0+3C69-AF00 + cheat + description:Start with 250 gold pieces + code:EC69-AFD0+DD69-AF00 + +cartridge sha256:41084f83e269d46b9d589f11c802a15e84fede57d604c7986053f2858f757adc + title:Archer Maclean's Super Dropzone (Europe) + cheat + description:Infinite lives + code:7E0025:04 + cheat + description:Infinite bombs + code:7E0026:04 + +cartridge sha256:0f474dafe5a26f3dea491d18073dd490d2f1f91313a7e91086565510d38d9a09 + title:Ardy Lightfoot (USA) + cheat + description:Invincibility + code:2D3F-446D+2D8F-3407 + cheat + description:Infinite lives + code:C268-CF0D + +cartridge sha256:14d3ece30898587eda20c661a4a55ec595ba6352ca1f0bfc177542aa0eef0039 + title:Arkanoid - Doh It Again (USA) + cheat + description:Infinite lives + code:82B8-1704 + cheat + description:"S" capsule gives you the longest paddle + code:D762-14D5 + cheat + description:"S" capsule gives you the laser paddle + code:D062-14D5 + cheat + description:Force field lasts until end of level + code:C2BD-3F60 + cheat + description:Keep current paddle when you get force field + code:DD66-CFA5 + +cartridge sha256:55e57c5e012583ff0fafd1aee16b3f8269ee2b34fe10f10b93ba0dde72f2b78d + title:Art of Fighting (USA) + cheat + description:Infinite health + code:CB3C-57AF+3E38-5DDF+6238-5D0F + cheat + description:Infinite time + code:C235-5DA4 + +cartridge sha256:d54d2703e474d7f469766d2d095ffcbbcab893e3fe58bbbcc57e24082a44bb40 + title:Asterix (Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:2D68-ADAD+A968-AF0D + cheat + description:Infinite health + code:82E9-6F64 + cheat + description:Infinite lives + code:82E0-6D04 + cheat + description:Infinite health (alt) + code:7E05F0:03 + cheat + description:Infinite lives (alt) + code:7E05FC:09+7E05FD:09 + cheat + description:Infinite time + code:7E05F7:09+7E05F8:09+7E05F9:09 + cheat + description:Infinite coins + code:7E05EE:09+7E05EF:09 + +cartridge sha256:d9127808fb02c47dd74fd22f39582c69f19936a794a8efc153cc0e51a0d4d782 + title:Asterix & Obelix (Europe) (En,Fr,De,Es) + cheat + description:Infinite health + code:7E008C:28 + cheat + description:Infinite lives + code:7E101D:09 + cheat + description:Infinite time + code:7E1076:27 + cheat + description:Always Magic Chicken + code:7E008E:04 + cheat + description:Moon jump (disable to drop back down) + code:7E007D:C0 + +cartridge sha256:2431f8dc067ba27c6c3a846929f3deac6a45aa53a9a9ac20ede8ec5ca6854ea2 + title:Axelay (USA) + cheat + description:Invincibility + code:2D87-AD04 + cheat + description:Infinite lives + code:A2AE-DF6D + cheat + description:Infinite lives (alt) + code:C2AE-DF6D+C28F-04D7 + cheat + description:Infinite credits + code:C2C5-DDDF + cheat + description:Don't lose weapon when hit + code:8285-AF07+82AA-676D + cheat + description:Hit anywhere + code:C93C-DD0F+C9BD-D408+DD36-D70F+DD3B-DF0F + cheat + description:Start with 1 credit + code:D766-D7A7 + cheat + description:Start with 2 credits + code:D066-D7A7 + cheat + description:Start with 3 credits + code:D966-D7A7 + cheat + description:Start with 4 credits + code:D166-D7A7 + cheat + description:Start with 6 credits + code:D666-D7A7 + cheat + description:Start with 7 credits + code:DB66-D7A7 + cheat + description:Start with 8 credits + code:DC66-D7A7 + cheat + description:Start with 9 credits + code:D866-D7A7 + cheat + description:Start with 1 life + code:DF21-AD04 + cheat + description:Start with 2 lives + code:D421-AD04 + cheat + description:Start with 5 lives + code:D921-AD04 + cheat + description:Start with 7 lives + code:D521-AD04 + cheat + description:Start with 9 lives + code:DB21-AD04 + cheat + description:Start with 15 lives + code:DE21-AD04 + cheat + description:Start with 25 lives + code:FB21-AD04 + cheat + description:Start with 50 lives + code:7421-AD04 + cheat + description:Start with 75 lives + code:0821-AD04 + cheat + description:Start with 99 lives + code:1721-AD04 + cheat + description:Start on Stage 2 + code:CBB7-AFA7+DFB7-A4D7+DDB7-A407 + cheat + description:Start on Stage 3 + code:CBB7-AFA7+D4B7-A4D7+DDB7-A407 + cheat + description:Start on Stage 4 + code:CBB7-AFA7+D7B7-A4D7+DDB7-A407 + cheat + description:Start on Stage 5 + code:CBB7-AFA7+D0B7-A4D7+DDB7-A407 + cheat + description:Start on Stage 6 + code:CBB7-AFA7+D9B7-A4D7+DDB7-A407 + cheat + description:Infinite lives (alt 2) + code:7E005E:02 + cheat + description:Have 1st weapon - Straight Laser + code:7E0330:02 + cheat + description:Have 1st weapon - Round Vulcan + code:7E0330:03 + cheat + description:Have 1st weapon - Wind Laser + code:7E0330:05 + cheat + description:Have 1st weapon - Explosion Bomb + code:7E0330:06 + cheat + description:Have 1st weapon - Macro Missiles + code:7E0330:07 + cheat + description:Have 1st weapon - Cluster Bomb + code:7E0330:09 + cheat + description:Have 1st weapon - Morning Star + code:7E0330:0A + cheat + description:Have 1st weapon - Needle Cracker + code:7E0330:0B + cheat + description:Have 2nd weapon - Straight Laser + code:7E0332:02 + cheat + description:Have 2nd weapon - Round Vulcan + code:7E0332:03 + cheat + description:Have 2nd weapon - Wind Laser + code:7E0332:05 + cheat + description:Have 2nd weapon - Explosion Bomb + code:7E0332:06 + cheat + description:Have 2nd weapon - Macro Missiles + code:7E0332:07 + cheat + description:Have 2nd weapon - Cluster Bomb + code:7E0332:09 + cheat + description:Have 2nd weapon - Morning Star + code:7E0332:0A + cheat + description:Have 2nd weapon - Needle Cracker + code:7E0332:0B + cheat + description:Have 3rd weapon - Straight Laser + code:7E0334:02 + cheat + description:Have 3rd weapon - Round Vulcan + code:7E0334:03 + cheat + description:Have 3rd weapon - Wind Laser + code:7E0334:05 + cheat + description:Have 3rd weapon - Explosion Bomb + code:7E0334:06 + cheat + description:Have 3rd weapon - Macro Missiles + code:7E0334:07 + cheat + description:Have 3rd weapon - Cluster Bomb + code:7E0334:09 + cheat + description:Have 3rd weapon - Morning Star + code:7E0334:0A + cheat + description:Have 3rd weapon - Needle Cracker + code:7E0334:0B + +cartridge sha256:9e6ebebcf14609c2a38a5f4409d0c8c859949cded70c5b6fd16fd15d9983d9d3 + title:B.O.B. (USA) + cheat + description:Infinite health (P) + code:C221-0D6D + cheat + description:Infinite lives + code:826E-0F0D + cheat + description:Infinite lives (alt) + code:4A6E-0F0D + cheat + description:Infinite time + code:C267-C0DD + cheat + description:Infinite weapons + code:8B37-A704 + cheat + description:Infinite Remotes + code:8BC7-3FE5 + cheat + description:Infinite Remotes (alt) + code:3CC7-3F85 + cheat + description:Infinite weapons (except for Flame) + code:3C37-A7D4 + cheat + description:Max weapons on pick-up + code:DDC0-C770 + cheat + description:Slow down timer + code:CD61-0D64 + cheat + description:Speed up timer + code:7961-0D64 + cheat + description:Start with 20 3-way + code:F0A6-1D59 + cheat + description:Start with 20 Flame + code:F0A6-1FE9 + cheat + description:Start with 20 Rocket + code:F0A6-1759 + cheat + description:Start with 20 Bolt + code:F0AB-1DE9 + cheat + description:Start with 20 Wave + code:F0AB-1459 + cheat + description:Start with 3 Flash Remotes + code:DDA8-1F89 + cheat + description:Start with 3 Shield Remotes + code:DFA8-1F89 + cheat + description:Start with 3 Umbrella Remotes + code:D4A8-1F89 + cheat + description:Start with 3 Helicopter Hat Remotes + code:D0A8-1F89 + cheat + description:Start with 3 Floating Bomb Remotes + code:D9A8-1F89 + cheat + description:Start with 6 of selected remote + code:D1A8-1479 + cheat + description:Start with 15 of selected remote + code:DEA8-1479 + cheat + description:Start with 1 life + code:DD66-0DDD + cheat + description:Start with 9 lives + code:D666-0DDD + cheat + description:Start with 6 lives + code:D966-0DDD + cheat + description:Infinite health (P) (alt) + code:7E0221:30 + cheat + description:Infinite E + code:7E0222:30 + cheat + description:Infinite weapons (except for Flame) (alt) + code:00EB3C:EA + cheat + description:Infinite Remotes (alt 2) + code:8DAF36:EA + cheat + description:Infinite time (alt) + code:7E0F42:3B + cheat + description:Infinite Flash Remotes + code:7E0209:63 + cheat + description:Infinite Shield Remotes + code:7E020A:63 + cheat + description:Infinite Umbrella Remotes + code:7E020B:63 + cheat + description:Infinite Spring Remotes + code:7E020C:63 + cheat + description:Infinite Helicopter Hat Remotes + code:7E020D:63 + cheat + description:Infinite Floating Bomb Remotes + code:7E020E:63 + cheat + description:Max weapons on pick-up (alt) + code:8DA24C:00 + +cartridge sha256:e25d052d25264a14c4904aebc383482577bb5d2bb135f3ece88b1b7b0456a6bc + title:Ballz 3D - Fighting at Its Ballziest (USA) + cheat + description:Infinite time + code:C295-ED64+C296-E7D4 + cheat + description:Always fight Kronk + code:CB82-EF0D+D082-EF6D+DD82-EFAD + cheat + description:Always fight Boomer + code:CB82-EF0D+D682-EF6D+DD82-EFAD + cheat + description:Always fight Bruiser + code:CB82-EF0D+DA82-EF6D+DD82-EFAD + cheat + description:Always fight Turbo + code:CB82-EF0D+FD82-EF6D+DD82-EFAD + cheat + description:Always fight Tsunami + code:CB82-EF0D+F082-EF6D+DD82-EFAD + cheat + description:Always fight Yoko + code:CB82-EF0D+F682-EF6D+DD82-EFAD + cheat + description:Always fight Divine + code:CB82-EF0D+FA82-EF6D+DD82-EFAD + cheat + description:Always fight Crusher + code:CB82-EF0D+4D82-EF6D+DD82-EFAD + cheat + description:Death match + code:CDE8-87AF + cheat + description:Start rounds with 10 seconds + code:DC78-E7AD + cheat + description:Start rounds with 20 seconds + code:F078-E7AD + cheat + description:Start rounds with 30 seconds + code:F378-E7AD + cheat + description:Start rounds with 40 seconds + code:4678-E7AD + cheat + description:Start rounds with 50 seconds + code:7478-E7AD + cheat + description:Start rounds with 60 seconds + code:7A78-E7AD + cheat + description:Start rounds with 70 seconds + code:0178-E7AD + cheat + description:Start with with 1/4 energy + code:4EDC-7760 + cheat + description:Start with with 1/2 energy + code:9EDC-7760 + cheat + description:Start with with 3/4 energy + code:BEDC-7760 + +cartridge sha256:865919b25a9d241c907bcda18b380e3c704f33f4997ad44559046f0f08c4968b + title:Barbie Super Model (USA) + cheat + description:Infinite chances + code:C229-DF07 + +cartridge sha256:fe1ad128313b2b9a47f89cf0d95d4c0cc2cb35a817ac5d915ee6c4d98d47d675 + title:Barkley Shut Up and Jam! (USA) + cheat + description:Infinite time + code:7E0780:47 + +cartridge sha256:e2be173c77bd1957787be36d13334f655e14d32dad99cacb0fd5e5fc65d96fa1 + title:Bassin's Black Bass (USA) + cheat + description:Always catch a 60.32 pound fish + code:CBCA-A4D3 + cheat + description:Always catch a 75.68 pound fish + code:CBCA-A4D3+D3CA-A463 + cheat + description:Always catch a largemouth bass + code:CBC8-A403+DDC8-A463+3CC8-A4A3 + cheat + description:Always have all lures (open the lure menu, close it, open it again to have all lures) + code:CBEA-DF60+DFEA-DFA0+B2EA-D4D0+4BEA-D4A0 + +cartridge sha256:db1ac03cc8b7daaa812da239029bcf999b30b2afe1c03d51f7ae849a796617ea + title:BASS Masters Classic - Pro Edition (USA) + cheat + description:Start with $65,380 + code:EE40-BA86 + cheat + description:Infinite money + code:7E2242:FF + +cartridge sha256:e36aaba64be016cabc33a2dcf88913341e2edacc722e2a1ebe04eccda2a5d6e7 + title:Batman Forever (USA) + cheat + description:Straight low punches are super strong + code:EE22-C70B + cheat + description:Straight high punches are super strong + code:EE20-3D0B + cheat + description:Straight low kicks are super strong + code:EE29-4F0B + cheat + description:Straight high kicks are super strong + code:EE2C-44AB + cheat + description:Crouching low punches are super strong + code:EE26-14AC + cheat + description:Crouching high punches are super strong + code:EE30-3FA6 + cheat + description:Crouching low kicks are super strong + code:EE3F-3D06 + cheat + description:Crouching high kicks are super strong + code:EE3A-CF06 + cheat + description:Straight low punches do no damage + code:DD22-C70B + cheat + description:Straight high punches do no damage + code:DD20-3D0B + cheat + description:Straight low kicks do no damage + code:DD29-4F0B + cheat + description:Straight high kicks do no damage + code:DD2C-44AB + cheat + description:Crouching low punches do no damage + code:DD26-14AC + cheat + description:Crouching high punches do no damage + code:DD30-3FA6 + cheat + description:Crouching low kicks do no damage + code:DD3F-3D06 + cheat + description:Crouching high kicks do no damage + code:DD3A-CF06 + cheat + description:Start with half energy after your first life + code:4D2C-4D07+4DCE-1465 + cheat + description:Play as an Inmate + code:F43C-3B10 + cheat + description:Play as a Clown + code:F03C-3B10 + cheat + description:Play as Two-Face + code:F63C-3B10 + cheat + description:Play as a Riddler Thug + code:FC3C-3B10 + cheat + description:Play as the Muscle Riddler + code:FA3C-3B10 + cheat + description:Start with 1 life + code:DDB3-47D4 + cheat + description:Start with 3 lives + code:D4B3-47D4 + cheat + description:Start with 10 lives + code:DBB3-47D4 + cheat + description:Infinite health - P1 + code:7E132C:FF + cheat + description:Infinite health - P2 + code:7E132E:FF + cheat + description:Infinite lives + code:7E0017:09 + cheat + description:One hit kills enemy #1 + code:7E1330:00 + +cartridge sha256:f8d5c51f74df33edc827fbf8df7aab70160770ab0a896db6e59438ad9208cc6e + title:Batman Returns (USA) + cheat + description:Invincibility + code:2DAA-1FA4+40A7-4F0D + cheat + description:Infinite health + code:C9A7-C7A4 + cheat + description:Infinite lives (3/4 view levels) + code:C9A5-1764 + cheat + description:Infinite special moves + code:C92D-4FDD + cheat + description:Protection from some hazards + code:C9A7-C404 + cheat + description:Cape sweep uses up no health + code:DDAE-3707 + cheat + description:Spear gun uses up no health + code:DD2F-4FAD + cheat + description:Cape sweep uses up more health + code:FDAE-3707 + cheat + description:Spear gun uses up more health + code:FD2F-4FAD + cheat + description:Maximum health from hearts + code:DD2E-3D6B + cheat + description:Cape sweep does more damage + code:F9CF-4F05 + cheat + description:Normal punch does more damage + code:F9CD-4705 + cheat + description:Normal knee does more damage + code:F9CD-4765 + cheat + description:Jump kick does more damage + code:F9CF-4D05+F9CF-4DD5 + cheat + description:Cape sweep does mega-damage + code:7DCF-4F05 + cheat + description:Normal punch does mega-damage + code:7DCD-4705 + cheat + description:Normal knee does mega-damage + code:7DCD-4765 + cheat + description:Jump kick does mega-damage + code:7DCF-4D05+7DCF-4DD5 + cheat + description:Cape sweep does less damage + code:D4CF-4F05 + cheat + description:Normal punch does less damage + code:D4CD-4705 + cheat + description:Normal knee does less damage + code:D4CD-4765 + cheat + description:Jump kick does less damage + code:D4CF-4D05+D4CF-4DD5 + cheat + description:Enable stage select + code:F76C-1FDF+616C-1F0F+CEC8-376F+C2E8-1078 + cheat + description:Start with 9 + code:DB68-4F00 + cheat + description:Start with 6 test tubes + code:D16F-4464+D1C0-4DD7 + cheat + description:Start with 9 test tubes + code:DB6F-4464+DBC0-4DD7 + cheat + description:Enemy 1 has 0 health + code:7E0567:00 + cheat + description:Enemy 2 has 0 health + code:7E0576:00 + cheat + description:Enemy 3 has 0 health + code:7E0666:00 + cheat + description:Enemy 4 has 0 health + code:7E0756:00 + +cartridge sha256:51cc42c58145f3e33b762e8ff36e9a9b7016ca831306d0d5f84830948a1a5967 + title:Batman - Revenge of the Joker (USA) (Proto) + cheat + description:Invincibility + code:2DA7-4460 + cheat + description:Infinite health + code:C2EF-1FA8 + cheat + description:Infinite lives + code:8263-44DD + cheat + description:Infinite health (alt) + code:7E0353:07+7E0355:07 + cheat + description:Infinite lives (alt) + code:7E0356:03+7E0358:03 + +cartridge sha256:983022203546e031773db0d1af7552c489187954882843f13ff123f09064c1d3 + title:Battle Blaze (USA) + cheat + description:Infinite continues + code:C285-D4AB + cheat + description:Infinite health (disable at end of round) - P1 + code:7E06DC:C0 + cheat + description:Infinite health (disable at end of round) - P2 + code:7E0704:C0 + cheat + description:No health - P1 + code:7E06DC:00 + cheat + description:No health - P2 + code:7E0704:00 + +cartridge sha256:32f42fda0667d9435a2de84c7ce7b067bcbab1164f8f6d837992ad6cfac4f8de + title:Battle Clash (USA) + cheat + description:Infinite health + code:C234-3FD3 + cheat + description:Protection from most enemy attacks + code:C234-3FD3 + cheat + description:Infinite time + code:C268-CFA5 + cheat + description:Weapon charges faster + code:D9A9-1DA7 + cheat + description:Weapon charges much faster + code:FDA9-1DA7 + cheat + description:Once charged, weapon always stays charged + code:1DAA-3FAF + cheat + description:Start in Cairo instead of New York + code:33EE-3D1F + cheat + description:Fight Garam at New York + code:CBAB-CDA0+DDAB-CF00+DDAB-CFD0 + cheat + description:Fight Scarab at Cairo + code:CBAB-CDA0+DDAB-CF00+DFAB-CFD0 + cheat + description:Fight Lorca at London + code:CBAB-CDA0+DDAB-CF00+D4AB-CFD0 + cheat + description:Fight Artemis at Andes + code:CBAB-CDA0+DDAB-CF00+D7AB-CFD0 + cheat + description:Fight Schneider at Kyoto + code:CBAB-CDA0+DDAB-CF00+D0AB-CFD0 + cheat + description:Fight Ivan at Oceania + code:CBAB-CDA0+DDAB-CF00+D9AB-CFD0 + cheat + description:Fight Valius at Babel + code:CBAB-CDA0+DDAB-CF00+D1AB-CFD0 + cheat + description:Fight Baron at Moonbase Luna + code:CBAB-CDA0+DDAB-CF00+D5AB-CFD0 + cheat + description:Fight Thanatos at last stage + code:CBAB-CDA0+DDAB-CF00+D6AB-CFD0 + cheat + description:Infinite health - P1 + code:7E15C0:80 + cheat + description:One hit kills + code:7E15A0:00 + +cartridge sha256:36cbc43a3ec85f235ecb6e0d5b134f069b619d3cc51e475427d3fcf8abb6ba44 + title:Battle Zeque Den (Japan) + cheat + description:Invincibility + code:D781-B386+FC3C-34A9 + cheat + description:Invincibility (alt) + code:7EB26A:03 + cheat + description:Infinite lives + code:CE35-C7A9 + cheat + description:Infinite Special + code:82C2-C7D0 + cheat + description:One hit kills + code:3D6E-C4D5+436E-C405+846E-C465+2D6E-C4A5 + cheat + description:Infinite health + code:7EB246:4E + cheat + description:Infinite lives (alt) + code:7E0329:0A + cheat + description:Infinite Special (Red) + code:7EB24C:02 + cheat + description:Infinite Special (Blue) + code:7EB24C:04 + cheat + description:Infinite Special (Green) + code:7EB24C:06 + +cartridge sha256:c7f0269498d190e4fd0f6f880a148fbe3713cd3a632083bac1e5bd18f8172371 + title:Battletoads-Double Dragon (USA) + cheat + description:Infinite lives + code:40B8-04AF + cheat + description:Enemies have less health + code:DE6E-1466 + cheat + description:Abobo has less health + code:4EB7-1DD6 + cheat + description:Big Blag has less health + code:4EB3-C4DB + cheat + description:Roper has less health + code:D7BA-3FA8 + cheat + description:Robo-Manus has less health + code:D7C5-3F66 + cheat + description:Start with 2 lives + code:DF60-D76D + cheat + description:Start with 10 lives + code:DB60-D76D + cheat + description:Start on level 2 with 11 lives + code:DD65-DD0D+CB66-D46D+DF66-D4AD + cheat + description:Start on level 3 with 11 lives + code:DD65-DD0D+CB66-D46D+D466-D4AD + cheat + description:Start on level 4 with 11 lives + code:DD65-DD0D+CB66-D46D+D766-D4AD + cheat + description:Start on level 5 with 11 lives + code:DD65-DD0D+CB66-D46D+D066-D4AD + cheat + description:Start on level 6 with 11 lives + code:DD65-DD0D+CB66-D46D+D966-D4AD + cheat + description:Invincibility (blinking) - P1 + code:7E1112:7F + cheat + description:Infinite health - P1 + code:7E003A:2F + cheat + description:Infinite lives - P1 + code:7E0026:05 + +cartridge sha256:b0dbd4d7e5689c32234e80b0c5362ef67c425ab72d6ddb49d1cb1133ef630ef7 + title:Battletoads in Battlemaniacs (USA) + cheat + description:Invincibility + code:2D20-34A8 + cheat + description:Invincibility in motorcycle levels + code:C2B4-3F68 + cheat + description:Infinite health + code:228E-34A0+2280-4DD9 + cheat + description:Infinite lives + code:8286-CF01 + cheat + description:Infinite lives - both players (except level 2, doesnメt work on falling) + code:8986-CF01 + cheat + description:Infinite continues - P1 + code:C96A-346F + cheat + description:Infinite continues - P2 + code:C96B-34DF + cheat + description:Infinite lives when falling + code:8026-CD08 + cheat + description:Longer invincibility after getting hit + code:6D20-34A8 + cheat + description:One hit kills + code:3D87-44A9+DD87-47D9+DD87-4709+CB80-4DD9+EE80-4D09+EE80-4D69+B280-4DA9 + cheat + description:Take less damage from hits + code:8280-4DD9 + cheat + description:Protection against most strength level 1 hits + code:82A7-3FAF + cheat + description:Protection against most strength level 2 hazards + code:8982-CFD1 + cheat + description:Easy finish on motorcycle levels. The turtle will keep going on until the end of the level. + code:C220-CF0C + cheat + description:Start with 2 lives + code:DF6D-0D0D + cheat + description:Start with 6 lives + code:D96D-0D0D + cheat + description:Start with 10 lives + code:DB6D-0D0D + cheat + description:Start with 0 continues + code:DD6D-04AD + cheat + description:Start with 5 continues + code:D96D-04AD + cheat + description:Start with 9 continues + code:DB6D-04AD + cheat + description:Infinite health - P1 + code:7E108E:0A + cheat + description:Infinite health - P2 + code:7E1090:0A + +cartridge sha256:0960f1de179f90e3d8488dacf09d5fe246fdb314913c370b3698dfdce58aa8ba + title:Bazooka Blitzkrieg (USA) + cheat + description:Immune to most damage + code:4AB5-3DAF + cheat + description:Fewer Missiles on pick-up + code:D9AC-1706 + cheat + description:More Missiles on pick-up + code:F0AC-1706 + cheat + description:Only 10 Missiles on pick-up (set Missiles to 10) + code:DCAB-14A6+DCAB-17A6 + cheat + description:30 Missiles allowed + code:F3AB-14A6+F3AB-17A6 + cheat + description:Less energy on pick-up from 'L' pods + code:D4AF-1406 + cheat + description:More energy on pick-up from 'L' pods + code:DCAF-1406 + cheat + description:A lot more energy on pick-up from 'L' pods + code:4EAF-1406 + cheat + description:Infinite health + code:7E0305:FF + cheat + description:Infinite Missiles + code:7E0304:14 + +cartridge sha256:d7271ca08400bbf5ae165b0aaa6e8a8a1b266f72e6e0ae10aae529732a472f7c + title:Beauty and the Beast (USA) + cheat + description:Invincibility (disable to pick up rocks, spikes still do damage) + code:3CC0-376A+3CC0-37AA + cheat + description:Invincibility (but you can't pick up objects) + code:2D6F-4DA0 + cheat + description:Invincibility after one hit + code:3C6F-4F00 + cheat + description:Infinite health + code:C2C8-3D0A + cheat + description:Infinite time + code:C269-6407 + cheat + description:Infinite flower time + code:C265-6407 + cheat + description:Infinite continues + code:C2E0-DF0F + cheat + description:Don't take damage from some enemies + code:3CC8-3D0A + cheat + description:No loss of light when the candle runs off the screen + code:4AC8-47A8 + cheat + description:Death flash time is longer + code:EE66-4FAA + +cartridge sha256:15d4fc90cb202a9391718cd40b9f0384165aef03018ed932540e8f7c18b397dd + title:Beavis and Butt-Head (USA) + cheat + description:Start with half health (1st life) + code:D16C-0D0D + cheat + description:Start with half health (after 1st life) + code:D161-AF0D + cheat + description:Almost infinite health + code:C22C-AF08 + cheat + description:Gun power-ups worth 30 + code:7DA8-C7DC + cheat + description:Gun power-ups worth 5 + code:D9A8-C7DC + cheat + description:Infinite lives + code:C267-A70D + cheat + description:Start with 2 life + code:DF6C-040D + cheat + description:Start with 4 lives + code:D76C-040D + cheat + description:Start with 10 lives + code:DB6C-040D + cheat + description:Invincibility after one hit + code:82EA-A4D1 + cheat + description:Everyone is invincible, including enemies + code:DDEA-AFA1+DDA0-04A8 + +cartridge sha256:4958eda26f2419f473449017c64121caee5e49c480ffa205422e7dd45cd23e31 + title:Bebe's Kids (USA) + cheat + description:Infinite health + code:7E047B:00 + cheat + description:Infinite time + code:7E0470:63 + cheat + description:Infinite lives + code:7E03C9:09 + +cartridge sha256:4d22279e534848012e0f1595468687742ae18cabc3fe44eeef938bc3a4dd08bf + title:Beethoven - The Ultimate Canine Caper! (USA) + cheat + description:Infinite health + code:823F-3D01 + cheat + description:Infinite time + code:8224-1705 + cheat + description:Infinite lives + code:82C8-3464 + cheat + description:Infinite health (alt) + code:7E1628:04 + cheat + description:Infinite time (alt) + code:7E1654:63 + cheat + description:Infinite lives (alt) + code:7E15C6:09 + +cartridge sha256:e4e9beaeeb3e968af772d1c4c9e4c1b4dfdba4e47c0205b458e1ab3a62a96060 + title:Best of the Best - Championship Karate (USA) + cheat + description:Almost infinite health + code:D68F-AD65 + cheat + description:Infinite special moves + code:828D-D409 + cheat + description:No special moves - P2 + code:BAC3-6F69 + cheat + description:Can play with any boxer (can't use special moves or get password) - P1 + code:D4C3-0DAD + cheat + description:Less strength + code:DCC3-0FDD + cheat + description:Less resistance + code:DCC3-0F0D + cheat + description:Less reflexes + code:DCC3-0F6D + cheat + description:More strength + code:74C3-0FDD + cheat + description:More resistance + code:74C3-0F0D + cheat + description:More reflexes + code:74C3-0F6D + cheat + description:Start with 1 special move + code:DFC3-6D69 + cheat + description:Start with 8 special moves + code:D6C3-6D69 + cheat + description:Infinite time + code:7E1A39:09 + cheat + description:No health - P2 + code:7E0222:00 + cheat + description:Max Reflexes + code:7E0459:63 + cheat + description:Max Resistance + code:7E0455:63 + cheat + description:Max Strength + code:7E0457:63 + +cartridge sha256:4cb601168c91fa0608c16a8cf2f292d991c6a5615d51861dee2f9b91c8d6bb19 + title:Big Sky Trooper (USA) + cheat + description:Infinite HP + code:7E1E0A:20 + cheat + description:Infinite hearts + code:7E1E10:99 + cheat + description:Infinite Power Pack meter + code:7E1E0C:20 + +cartridge sha256:91ba5691dea3cdf103177ae5779110fc372fce8229cf91f263073667e7a8b5b7 + title:Biker Mice from Mars (USA) + cheat + description:Infinite ammo + code:3CB8-4F63 + cheat + description:Infinite cash + code:8E89-C7DB + cheat + description:Infinite Shield/Armor + code:82B8-C76D + cheat + description:Infinite Skull effect + code:C263-CDDA + cheat + description:Infinite Star effect + code:8289-4F03 + cheat + description:Infinite Stopwatch effect + code:C26C-47D2 + cheat + description:Infinite ammo (alt) + code:7E17C6:03 + cheat + description:Max Engines + code:7EFE38:05 + cheat + description:Max Tires + code:7EFE3C:05 + cheat + description:Max Armor + code:7EFE40:05 + cheat + description:Max Tornado Shots + code:7E1F88:63 + cheat + description:Always finish 1st + code:7E0928:00 + +cartridge sha256:6fa6b8a8804ff6544bdedf94339a86ba64ce0b6dbf059605abb1cd6f102d3483 + title:Bill Laimbeer's Combat Basketball (USA) + cheat + description:2-point shots worth 3, 3-point shots worth 4 + code:76BF-A4AF + cheat + description:All shots worth 1 point + code:1BBF-A7DF+DFBF-A70F + cheat + description:All shots worth 3 points + code:1BBF-A7DF+D7BF-A70F + cheat + description:All shots worth 4 points + code:1BBF-A7DF+D0BF-A70F + cheat + description:All shots worth 5 points + code:1BBF-A7DF+D9BF-A70F + cheat + description:All shots worth 6 points + code:1BBF-A7DF+D1BF-A70F + cheat + description:Each half is 0:30 instead of 1:30 + code:DDB4-67DF + cheat + description:Each half is 2:30 + code:D4B4-67DF + cheat + description:Each half is 3:30 + code:D7B4-67DF + cheat + description:Each half is 4:30 + code:D0B4-67DF + cheat + description:Start with $65,296 instead of $10,000 + code:EEC5-6F16 + cheat + description:Start with $8,398,608 + code:6DC5-64C6 + cheat + description:Start with $16,721,680 + code:EEC5-64C6 + cheat + description:No money is deducted from your total when you trade a player (but you must have enough money to make the trade) + code:C2BE-6D4B+C2BE-644B + cheat + description:Trade players for free + code:C2BE-6D4B+C2BE-644B+6DBE-AD4B + cheat + description:Timer continues to count when it is normally stopped (time-out by pressing start) + code:DDB7-67DF + +cartridge sha256:de1de85ad549a6aaf0431cceb47cbd07e1f6e81f9e16fd62575305e2c1f06240 + title:BioMetal (USA) + cheat + description:Invincibility (blinking) + code:406D-DDD2 + cheat + description:Infinite lives + code:C26E-6D02 + cheat + description:Infinite charge + code:C262-0D62 + cheat + description:Hit anywhere + code:462E-0767+6D2E-0707+C927-6FD7 + cheat + description:Infinite lives (alt) + code:7E029D:0A + +cartridge sha256:3f030b6c6aa86bc4ab3d39568740d8c6b0ec3422a1964fe1b56e94de47dfa420 + title:Bishin Densetsu Zoku (Japan) + cheat + description:Infinite health + code:7E122C:50 + cheat + description:No car damage + code:7E0D9B:2F + cheat + description:Infinite time + code:7E0C96:00 + cheat + description:Infinite time (alt) + code:7E0C97:09 + +cartridge sha256:ff936a073032205daadfea3738526a381daf7e402e8216d08561ddca8ceaf526 + title:Bishoujo Senshi Sailormoon (Japan) + cheat + description:One hit kills + code:40FD-8FD0+40F8-ED69+40F9-74A1 + cheat + description:Invincibility + code:2D0D-E765 + cheat + description:Infinite health + code:8BFF-5F00+C9F9-87D1 + cheat + description:Infinite lives + code:C991-7FA0 + +cartridge sha256:8860380ae0afa280619fdca8723aed1393485a22bec442880acc75249cab37f4 + title:Bishoujo Senshi Sailormoon R (Japan) + cheat + description:Invincibility + code:2D0D-EFA5+2D0D-E4A5 + cheat + description:Infinite health + code:8BDC-7D61 + cheat + description:Infinite lives + code:C992-5460 + cheat + description:Infinite Special + code:C90F-E400 + cheat + description:One hit kills + code:40D3-5FA1+400D-7F05+40F5-5D00 + +cartridge sha256:328c8f57e2ea371f6fd5b8a9834c56e35eb3bfe710502dd80f370739f9ccb7e1 + title:Blackthorne (USA) + cheat + description:Infinite items (enable after obtaining first item, disable before getting next item, repeat this process) + code:89C6-1FD4 + cheat + description:Infinite health + code:7E0FC5:18 + cheat + description:3rd slot item mod + code:7E187A:03 + +cartridge sha256:0d4e0d134396bd1c7254cdc1da356eb944ca14910b6690f484a75a9c3a8106e7 + title:BlaZeon - The Bio-Cyborg Challenge (USA) + cheat + description:Invincibility + code:2D6D-A700 + cheat + description:Infinite lives + code:82B4-D4DD + cheat + description:Infinite lives (alt) + code:C2B4-D4DD+C2BD-64AD + cheat + description:Infinite Atomic Shields - Mars + code:C2C7-D7A7 + cheat + description:Infinite Hyper Bombs - Neptune + code:C2C3-DF67 + cheat + description:Start with 1 ship + code:DD6E-6707 + cheat + description:Start with 2 ships + code:DF6E-6707 + cheat + description:Start with 4 ships + code:D76E-6707 + cheat + description:Start with 5 ships + code:D06E-6707 + cheat + description:Start with 7 ships + code:D16E-6707 + cheat + description:Start with 10 ships + code:DB6E-6707 + cheat + description:Start with 26 ships + code:FB6E-6707 + cheat + description:Start on Stage 2 + code:DF6D-6D07 + cheat + description:Start on Stage 3 + code:D46D-6D07 + cheat + description:Start on Stage 4 + code:D76D-6D07 + cheat + description:Start on Stage 5 + code:D06D-6D07 + +cartridge sha256:99f40f06fa4dbeeea4fe67d2de5b4c1bf301bedac1958ba1c239dcaf39b0a998 + title:Blues Brothers, The (USA) + cheat + description:Invincibility + code:1DB3-14DF + cheat + description:Infinite health (1P game) + code:82A3-3F0D + cheat + description:Infinite health (2P game) + code:82AE-14D7 + cheat + description:Infinite lives + code:828F-34DF + cheat + description:Infinite time + code:C2B3-3764 + cheat + description:Infinite Discs + code:8289-CFDF + +cartridge sha256:d50ef11383d78544dbad4d350cfd1486fb28e459e208d1553acdecbd84a808b8 + title:Bobby's World (USA) (Proto) + cheat + description:Invincibility + code:2DB7-1DD8 + cheat + description:Infinite energy + code:82BC-1468 + cheat + description:Infinite lives + code:822D-17AF + +cartridge sha256:854d2492d1cb059749bb0904ca5f92a5eeec09167abf84f7cca4023b1819e4f0 + title:Bonkers (USA) + cheat + description:Invincibility + code:2DCD-C404 + cheat + description:Infinite health + code:89C4-1DDF + cheat + description:Infinite bombs + code:C9AB-CFDD + cheat + description:Infinite lives + code:C963-CD0F + cheat + description:Infinite dash + code:C98C-CD0F + +cartridge sha256:8f131182b286bd87f12cf4f00453336538ce690d0e1f0972ac0be98df4d48987 + title:Boogerman - A Pick and Flick Adventure (USA) + cheat + description:Infinite health + code:CDF7-57AD + cheat + description:Infinite lives + code:DDF0-740D + cheat + description:Infinite Loogies + code:DD5C-74A9 + cheat + description:Infinite Boogers + code:DD53-E760 + cheat + description:Infinite Belches + code:DD55-5F09 + cheat + description:Infinite Super Belches + code:DD51-8FA9 + cheat + description:Infinite Farts + code:DD54-87D1 + cheat + description:Infinite Super Farts + code:DD54-ED61 + cheat + description:Infinite Chili Belches and Farts + code:DDB8-5DD5 + cheat + description:Infinite Super Chili Belches and Farts + code:DDBB-8765 + cheat + description:Infinite Rocket Farts + code:DDFE-7FD1 + cheat + description:Get chili when hit + code:DFF2-7D05 + cheat + description:Get Milk when hit + code:DFFA-74A5 + cheat + description:Infinite health (alt) + code:7E0EF8:02 + cheat + description:Infinite Boogers (alt) + code:7E0224:20 + cheat + description:Infinite Belches and Farts (both kinds) + code:7E0226:20 + +cartridge sha256:e67940a2106c1507f3a8d38790f263bbbf814578ebf3dbc4e3eb6007d310793c + title:Boxing Legends of the Ring (USA) + cheat + description:Infinite super punches - P1 + code:C26D-3F05 + cheat + description:Infinite super punches - P2 or CPU + code:C260-C4A9 + cheat + description:Infinite strength beads + code:DD2B-17D9+C229-C4D9 + cheat + description:Infinite time per round + code:C2BA-A7A7 + cheat + description:Each round is 1 minute + code:DF8D-CDA7 + cheat + description:Each round is 2 minutes + code:D48D-CDA7 + cheat + description:Each round is 4 minutes + code:D08D-CDA7 + cheat + description:Each round is 5 minutes + code:D98D-CDA7 + cheat + description:Each round is 6 minutes + code:D18D-CDA7 + cheat + description:Both fighters start with no super punches + code:DD87-C4D4 + cheat + description:Both fighters start with 2 super punches + code:D487-C4D4 + cheat + description:Both fighters start with 3 super punches + code:D787-C4D4 + cheat + description:Create a stronger left jab + code:6DEE-CF4E + cheat + description:Create a stronger left hook body + code:6DEE-CFCE + cheat + description:Create a stronger left hook head + code:6DEE-C44E + cheat + description:Create a stronger left uppercut + code:6DEE-C4CE + cheat + description:Create a stronger right cross body + code:6DEE-C74E + cheat + description:Create a stronger right cross head + code:6DEE-C7CE + cheat + description:Create a stronger right uppercut + code:6DED-3D4E + cheat + description:Start on round 5 + code:338F-C7A4 + cheat + description:Start on round 12 + code:A38F-C7A4 + cheat + description:Infinite full stanima + code:7E05AF:0F + +cartridge sha256:f4666355e7fea434843dc6d5119673bd6c23e69b884aac0b382ff036997e52b5 + title:Brain Lord (USA) + cheat + description:9999 HP + code:7E08C2:0F+7E08C3:27 + cheat + description:9999 Max HP + code:7E08C4:0F+7E08C5:27 + cheat + description:255 Power + code:7E08CA:FF + cheat + description:Have the best status + code:7E08DD:00 + cheat + description:Move faster, same effect as wearing the Cloak + code:7E08D4:07 + cheat + description:Infinite G + code:7E0376:97 + cheat + description:Can access 13 spells + code:7E08D1:0D + cheat + description:Have Magic Shot spell + code:7E0910:02 + cheat + description:Have Magic Shield spell + code:7E0911:03 + cheat + description:Have Flame Ring spell + code:7E0912:04 + cheat + description:Have Fireball spell + code:7E0913:05 + cheat + description:Have Impulse spell + code:7E0914:06 + cheat + description:Have Lightning spell + code:7E0915:07 + cheat + description:Have Magic Missile spell + code:7E0916:08 + cheat + description:Have Bound spell + code:7E0917:09 + cheat + description:Have Ice spell + code:7E0918:0A + cheat + description:Have Phaser spell + code:7E0919:0B + cheat + description:Have Slow spell + code:7E091A:0E + cheat + description:Have Stop spell + code:7E091B:0F + cheat + description:Have Ghost spell + code:7E091C:10 + cheat + description:Quick spell charge + code:7E08C7:01 + cheat + description:Have the Iron Sword + code:7E0921:01+7E0920:02 + cheat + description:Have the Steel Buster + code:7E0921:01+7E0920:03 + cheat + description:Have the Platinum Sword + code:7E0921:01+7E0920:05 + cheat + description:Have the Battle Axe + code:7E0921:01+7E0920:06 + cheat + description:Have the Tomahawk + code:7E0921:01+7E0920:07 + cheat + description:Have the Rock Breaker + code:7E0921:01+7E0920:08 + cheat + description:Have the Great Axe + code:7E0921:01+7E0920:09 + cheat + description:Have the Boomerang + code:7E0921:01+7E0920:0A + cheat + description:Have the Chuckler + code:7E0921:01+7E0920:0B + cheat + description:Have the Mornin Star + code:7E0921:01+7E0920:0C + cheat + description:Have the Heavy Mall + code:7E0921:01+7E0920:0D + cheat + description:Have the Long Bow + code:7E0921:01+7E0920:0E + cheat + description:Have the Silver Bow + code:7E0921:01+7E0920:0F + cheat + description:Have the Lightning Bow + code:7E0921:01+7E0920:10 + cheat + description:Have the Fire Sword + code:7E0921:01+7E0920:12 + cheat + description:Have the Iron Helmet + code:7E0923:02+7E0922:02 + cheat + description:Have the Cross Helmet + code:7E0923:02+7E0922:03 + cheat + description:Have the Blackgold Helm + code:7E0923:02+7E0922:04 + cheat + description:Have the Warrior's Helm + code:7E0923:02+7E0922:05 + cheat + description:Have the Platinum Helm + code:7E0923:02+7E0922:06 + cheat + description:Have the Nameless Helm + code:7E0923:02+7E0922:07 + cheat + description:Have the Nameless Helm + code:7E0923:02+7E0922:08 + cheat + description:Have the Nameless Helm + code:7E0923:02+7E0922:09 + cheat + description:Have the Chain Mail + code:7E0925:03+7E0924:02 + cheat + description:Have the Banded Mail + code:7E0925:03+7E0924:03 + cheat + description:Have the Bone Mail + code:7E0925:03+7E0924:04 + cheat + description:Have the Plate Armor + code:7E0925:03+7E0924:05 + cheat + description:Have the Royal Armor + code:7E0925:03+7E0924:06 + cheat + description:Have the Cape + code:7E0925:03+7E0924:07 + cheat + description:Have the Nameless Armor + code:7E0925:03+7E0924:08 + cheat + description:Have the Nameless Armor + code:7E0925:03+7E0924:09 + cheat + description:Have the Round Shield + code:7E0927:04+7E0926:02 + cheat + description:Have the Kite Shield + code:7E0927:04+7E0926:03 + cheat + description:Have the Bone Shield + code:7E0927:04+7E0926:04 + cheat + description:Have the Warrior Shield + code:7E0927:04+7E0926:05 + cheat + description:Have the Battle Shield + code:7E0927:04+7E0926:06 + cheat + description:Have the Shield + code:7E0927:04+7E0926:07 + cheat + description:Have the Reviving Mirror + code:7E0929:05+7E0928:01 + cheat + description:Have the Debug Mirror (a debug item) + code:7E0929:05+7E0928:02 + cheat + description:Have the Wind Shoes + code:7E0929:05+7E0928:03 + cheat + description:Have the Spike Boots + code:7E0929:05+7E0928:04 + cheat + description:Have the Life Jade + code:7E092B:06+7E092A:01 + cheat + description:Have the Crimson Jade + code:7E092B:06+7E092A:02 + cheat + description:Have the Foundation Jade + code:7E092B:06+7E092A:03 + cheat + description:Have the Power Jade + code:7E092B:06+7E092A:04 + cheat + description:Have the Lightning Jade + code:7E092B:06+7E092A:05 + cheat + description:Have the Anger Jade + code:7E092B:06+7E092A:06 + cheat + description:Have the Water Jade + code:7E092B:06+7E092A:07 + cheat + description:Have the Deceased Jade + code:7E092B:06+7E092A:08 + cheat + description:Have the Light Jade + code:7E092B:06+7E092A:09 + cheat + description:Have the Key to the Seal + code:7E092D:07+7E092C:01 + cheat + description:Have the 3rd floor Key + code:7E092D:07+7E092C:02 + cheat + description:Have the 4th floor Key + code:7E092D:07+7E092C:03 + cheat + description:Have the Puzzle Key + code:7E092D:07+7E092C:04 + cheat + description:Have the Crossroads Key + code:7E092D:07+7E092C:05 + cheat + description:Have the Sky Room Key + code:7E092D:07+7E092C:06 + cheat + description:Have the Cave Room Key + code:7E092D:07+7E092C:07 + cheat + description:Have the Dark Room Key + code:7E092D:07+7E092C:08 + cheat + description:Have the Basement Key + code:7E092D:07+7E092C:09 + cheat + description:Have the Detour Key + code:7E092D:07+7E092C:0A + cheat + description:Have the Bottomless Key + code:7E092D:07+7E092C:0B + cheat + description:Have the Distance Key + code:7E092D:07+7E092C:0C + cheat + description:Have the Office Key + code:7E092D:07+7E092C:0D + cheat + description:Have the Flyer's Key + code:7E092D:07+7E092C:0E + cheat + description:Have the Steel Sky Key + code:7E092D:07+7E092C:0F + cheat + description:Have the Invisible Key + code:7E092D:07+7E092C:10 + cheat + description:Have the Underground Key + code:7E092D:07+7E092C:11 + cheat + description:Have the Control Key + code:7E092D:07+7E092C:12 + cheat + description:Have the Preparation Key + code:7E092D:07+7E092C:13 + cheat + description:Have the Laboratory Key + code:7E092D:07+7E092C:14 + cheat + description:Have the Power Room Key + code:7E092D:07+7E092C:15 + cheat + description:Have the Oblivion Key + code:7E092D:07+7E092C:16 + cheat + description:Have the Western Sky Key + code:7E092D:07+7E092C:1F + cheat + description:Have the Ocean Key + code:7E092D:07+7E092C:20 + cheat + description:Have the Under Ice Key + code:7E092D:07+7E092C:21 + cheat + description:Have the Waterfall Key + code:7E092D:07+7E092C:22 + cheat + description:Have the Flood Gate Key + code:7E092D:07+7E092C:23 + cheat + description:Have the Wave Key + code:7E092D:07+7E092C:24 + cheat + description:Have the Ice Key + code:7E092D:07+7E092C:25 + cheat + description:Have the Water-Air Key + code:7E092D:07+7E092C:26 + cheat + description:Have the Red Wing Key + code:7E092D:07+7E092C:27 + cheat + description:Have the 1st Gate Key + code:7E092D:07+7E092C:28 + cheat + description:Have the 2nd Gate Key + code:7E092D:07+7E092C:29 + cheat + description:Have the 3rd Gate Key + code:7E092D:07+7E092C:2A + cheat + description:Have the Sky Dragon Key + code:7E092D:07+7E092C:2B + cheat + description:Have the Land Dragon Key + code:7E092D:07+7E092C:2C + cheat + description:Have the Sea Dragon Key + code:7E092D:07+7E092C:2D + cheat + description:Have the Dead Dragon Key + code:7E092D:07+7E092C:2E + cheat + description:Have the Silence Key + code:7E092D:07+7E092C:33 + cheat + description:Have the Castle Key + code:7E092D:07+7E092C:34 + cheat + description:Have the Endless Key + code:7E092D:07+7E092C:35 + cheat + description:Have the Spirit Key + code:7E092D:07+7E092C:36 + cheat + description:Have the Destruction Key + code:7E092D:07+7E092C:37 + cheat + description:Have the Platinum Key + code:7E092D:07+7E092C:38 + cheat + description:Have the Night Key + code:7E092D:07+7E092C:39 + cheat + description:Have the Afterworld Key + code:7E092D:07+7E092C:3A + cheat + description:Have the Entropy Key + code:7E092D:07+7E092C:3B + cheat + description:Have the Fountain Key + code:7E092D:07+7E092C:3C + cheat + description:Have the Duplicate Key + code:7E092D:07+7E092C:3E + cheat + description:Have the Duplicate Key + code:7E092D:07+7E092C:3F + +cartridge sha256:5f1912fdac09cd60d3a8962cad3875c6221b38347f0e98abc5800c73214678a9 + title:Brainies, The (Europe) + cheat + description:Timer disable cheat to get score then re-enable + code:7E091C:17 + +cartridge sha256:9885ca148d32c4df6230642bcfa153f7e51b9559415042a831db14d07b3e6c3d + title:Brainies, The (USA) + cheat + description:Infinite time + code:C262-0DD4 + cheat + description:Infinite continues + code:C262-67AF + cheat + description:Start with and always have 9 Jokers + code:DBCC-6F6D + cheat + description:Start on level 25 + code:FC63-AF6D + cheat + description:Start on level 50 + code:7763-AF6D + cheat + description:Start on level 75 + code:0A63-AF6D + cheat + description:Start on level 100 + code:1963-AF6D + +cartridge sha256:bbde8b46c7262f9d4a5b3926a00850cb00b4f7711f6421f0adf4e2b0c847a5d6 + title:Bram Stoker's Dracula (USA) + cheat + description:Infinite energy + code:C263-0F2F + cheat + description:Infinite lives + code:C268-ADBF + cheat + description:Infinite pistol ammo + code:C92B-A4DA + cheat + description:Infinite shotgun ammo + code:C926-64AA + cheat + description:Turbo walking + code:3CC2-6F6D + cheat + description:Infinite missile weapon + code:C927-D762 + cheat + description:One hit kills all enemies, except bosses + code:6D68-DFFF + cheat + description:Freeze most ground enemies + code:4AA8-64D4 + cheat + description:Freeze most aerial enemies + code:4AAB-6F64 + cheat + description:Start at the final battle + code:FDEC-0F03 + +cartridge sha256:130a74e76369b0ec4d6378a014550921433f1ae1ac1dddffb51f77c9f21a818f + title:Brandish (USA) + cheat + description:Have over 10,000,000 gold + code:FD53-A3D7 + cheat + description:Sell an item for max gold + code:D484-1405+6D84-14D5 + cheat + description:Luck stays maxed out + code:6D3B-4FD2 + cheat + description:Map gets filled when entering a level + code:6D02-770B+3C02-776B + +cartridge sha256:044b61613ed66eae08abd5fa5dcd13b24aab11a942e3309cdff624d198c47440 + title:Brawl Brothers (USA) + cheat + description:Invincibility and infinite special attack + code:6D63-1791+DF63-17B1 + cheat + description:Infinite health + code:A961-3DB1 + cheat + description:One hit kills on most enemies + code:EE6B-CF21+EE6B-C4F1+406B-C4B1 + cheat + description:Bosses die immediately + code:EE6E-1D21+EE6E-1FF1+406E-1FB1 + cheat + description:Hit anywhere - both players + code:40C2-44B9+40C2-4729+40CC-4D99+40CD-1DF9+40CE-4429 + cheat + description:Invincibility - P1 + code:7E0908:01 + cheat + description:Invincibility - P2 + code:7E09D8:01 + cheat + description:Infinite health - P1 + code:7E0924:50 + cheat + description:Infinite health - P2 + code:7E09F4:50 + cheat + description:Infinite lives - P1 + code:7E0946:09 + cheat + description:Infinite lives - P2 + code:7E0A16:09 + cheat + description:One hit kills on most enemies (alt) + code:7E0B94:00+7E0919:00+7E0D34:00+7E0C64:00+7E0AC4:00 + cheat + description:Have Lots of Kills - P1 + code:7E0C34:FF + cheat + description:Play as Dieter (glitchy) - P1 + code:7E0920:0A + cheat + description:Play as Dieter (glitchy) - P2 + code:7E09F0:0A + +cartridge sha256:aad8c9be1b7a9662256b0c3d76f5b7a273bcd497aa838232d307e9f2e80cf699 + title:BreakThru! (USA) + cheat + description:Infinite time + code:7E125B:FF + +cartridge sha256:cbc496a7879ba78f32c51c3df4ba1a1a42f17d78d48a39ea9c709d1ad18cb8df + title:Breath of Fire (USA) + cheat + description:9999 EXP after every battle + code:336F-172D + cheat + description:Infinite usable items in menu + code:DEEE-C0B4 + cheat + description:Infinite Gold + code:8EE1-C7F3+8EE5-CD23+8EEE-CF23 + cheat + description:Create a new character at level 5 + code:D9BF-CD69 + cheat + description:Create a new character with 153 max HP + code:BBBF-CFD9 + cheat + description:Create a new character with 153 HP + code:BBBF-CF69 + cheat + description:Create a new character with 20 max AP + code:F0BF-C4D9 + cheat + description:Create a new character with 20 AP + code:F0BF-C469 + cheat + description:Create a new character with INT at 22 + code:F1B4-CD09 + cheat + description:Create a new character with Agility at 22 + code:F1B4-CD69 + cheat + description:Create a new character with Fate at 40 + code:46B4-CFD9 + cheat + description:Create a new character with strength at 50 + code:74BF-C7A9 + cheat + description:Create a new character with Vigor at 50 + code:74B4-CDD9 + cheat + description:Ryu starts with Tri-Rang + code:9EB7-CDD9 + cheat + description:Ryu starts with EmporSD + code:D6B7-CDD9 + cheat + description:Ryu starts with DragonSH + code:90B7-CD69 + cheat + description:Ryu starts with LifeAR + code:F2B7-CFD9 + cheat + description:Ryu starts with DragonHT + code:6CB7-CF69 + cheat + description:Nina starts with PowerRP + code:F2BB-CDD9 + cheat + description:Nina starts with MaskSH + code:97BB-CD69+4FBB-CDA9 + cheat + description:Nina starts with ClearCL + code:43BB-CFD9 + cheat + description:Nina starts with LoveHT + code:56BB-CF69+4FBB-CFA9 + cheat + description:Bo starts with HeroBW + code:98B1-CDD9 + cheat + description:Bo starts with IcyAR + code:FFB1-CD69 + cheat + description:Bo starts with CursedHT + code:18B1-CFD9 + cheat + description:Ox starts with Mallet + code:41BA-CDD9 + cheat + description:Ox starts with StarSH + code:60BA-CD69 + cheat + description:Ox starts with WorldAR + code:49BA-CFD9 + cheat + description:Ox starts with CursedHT + code:18BA-CF69 + cheat + description:Gobi starts with Sleeper + code:76BE-CDD9 + cheat + description:Gobi starts with StarSH + code:60BE-CD69+4FBE-CDA9 + cheat + description:Gobi starts with SpineCL + code:F0BE-CFD9 + cheat + description:Gobi starts with CursedHT + code:18BE-CF69 + cheat + description:Karn starts with DarkDR + code:0AB4-3DD9 + cheat + description:Karn starts with StarSH + code:60B4-3D69+4FB4-3DA9 + cheat + description:Karn starts with QuartzAR + code:FEB4-3FD9 + cheat + description:Karn starts with CursedHT + code:18B4-3F69 + cheat + description:Mogu starts with MystCW + code:7EB9-3DD9 + cheat + description:Mogu starts with StarSH + code:60B9-3D69+4FB9-3DA9 + cheat + description:Mogu starts with FlameAR + code:D3B9-3FD9 + cheat + description:Mogu starts with CursedHT + code:18B9-3F69+4FB9-3FA9 + cheat + description:Bleu starts with GlowCN + code:4EB6-3DD9 + cheat + description:Bleu starts with MaskSH + code:97B6-3D69 + cheat + description:Bleu starts with ClearCL + code:43B6-3FD9 + cheat + description:Bleu starts with CursedHT + code:18B6-3F69 + cheat + description:Character 1 - Max LEVEL + code:7E104A:FF + cheat + description:Character 1 - Infinite HP + code:7E104E:E7+7E104F:03 + cheat + description:Character 1 - Max HP + code:7E104C:E7+7E104D:03 + cheat + description:Character 1 - Infinite AP + code:7E1052:E7+7E1053:03 + cheat + description:Character 1 - Max AP + code:7E1050:E7+7E1051:03 + cheat + description:Character 1 - Max Str + code:7E1057:FF + cheat + description:Character 1 - Max Vigor + code:7E1058:FF + cheat + description:Character 1 - Max Wisdom + code:7E1059:FF + cheat + description:Character 1 - Max Agil + code:7E105A:FF + cheat + description:Character 1 - Max MAG + code:7E105B:FF + cheat + description:Character 1 - Max Luck + code:7E105C:FF + cheat + description:Character 1 - Max ATK + code:7E105D:E7+7E105E:03 + cheat + description:Character 1 - Max DEF + code:7E105F:E7+7E1060:03 + cheat + description:Character 1 - Max INT + code:7E1061:FF + cheat + description:Character 1 - Max ACT + code:7E1062:FF + cheat + description:Character 1 - Max FATE + code:7E1063:FF + cheat + description:Character 2 - Max LEVEL + code:7E10EA:FF + cheat + description:Character 2 - Infinite HP + code:7E10EE:E7+7E10EF:03 + cheat + description:Character 2 - Max HP + code:7E10EC:E7+7E10ED:03 + cheat + description:Character 2 - Infinite AP + code:7E10F2:E7+7E10F3:03 + cheat + description:Character 2 - Max AP + code:7E10F0:E7+7E10F1:03 + cheat + description:Character 2 - Max Str + code:7E10F7:FF + cheat + description:Character 2 - Max Vigor + code:7E10F8:FF + cheat + description:Character 2 - Max Wisdom + code:7E10F9:FF + cheat + description:Character 2 - Max Agil + code:7E10FA:FF + cheat + description:Character 2 - Max MAG + code:7E10FB:FF + cheat + description:Character 2 - Max Luck + code:7E10FC:FF + cheat + description:Character 2 - Max ATK + code:7E10FD:E7+7E10FE:03 + cheat + description:Character 2 - Max DEF + code:7E10FF:E7+7E1100:03 + cheat + description:Character 2 - Max INT + code:7E1101:FF + cheat + description:Character 2 - Max ACT + code:7E1102:FF + cheat + description:Character 2 - Max FATE + code:7E1103:FF + cheat + description:Character 3 - Max LEVEL + code:7E118A:FF + cheat + description:Character 3 - Infinite HP + code:7E118E:E7+7E118F:03 + cheat + description:Character 3 - Max HP + code:7E118C:E7+7E118D:03 + cheat + description:Character 3 - Infinite AP + code:7E1192:E7+7E1193:03 + cheat + description:Character 3 - Max AP + code:7E1190:E7+7E1191:03 + cheat + description:Character 3 - Max Str + code:7E1197:FF + cheat + description:Character 3 - Max Vigor + code:7E1198:FF + cheat + description:Character 3 - Max Wisdom + code:7E1199:FF + cheat + description:Character 3 - Max Agil + code:7E119A:FF + cheat + description:Character 3 - Max MAG + code:7E119B:FF + cheat + description:Character 3 - Max Luck + code:7E119C:FF + cheat + description:Character 3 - Max ATK + code:7E119D:E7+7E119E:03 + cheat + description:Character 3 - Max DEF + code:7E119F:E7+7E11A0:03 + cheat + description:Character 3 - Max INT + code:7E11A1:FF + cheat + description:Character 3 - Max ACT + code:7E11A2:FF + cheat + description:Character 3 - Max FATE + code:7E11A3:FF + cheat + description:Character 4 - Max LEVEL + code:7E122A:FF + cheat + description:Character 4 - Infinite HP + code:7E122E:E7+7E122F:03 + cheat + description:Character 4 - Max HP + code:7E122C:E7+7E122D:03 + cheat + description:Character 4 - Infinite AP + code:7E1232:E7+7E1233:03 + cheat + description:Character 4 - Max AP + code:7E1230:E7+7E1231:03 + cheat + description:Character 4 - Max Str + code:7E1237:FF + cheat + description:Character 4 - Max Vigor + code:7E1238:FF + cheat + description:Character 4 - Max Wisdom + code:7E1239:FF + cheat + description:Character 4 - Max Agil + code:7E123A:FF + cheat + description:Character 4 - Max MAG + code:7E123B:FF + cheat + description:Character 4 - Max Luck + code:7E123C:FF + cheat + description:Character 4 - Max ATK + code:7E123D:E7+7E123E:03 + cheat + description:Character 4 - Max DEF + code:7E123F:E7+7E1240:03 + cheat + description:Character 4 - Max INT + code:7E1241:FF + cheat + description:Character 4 - Max ACT + code:7E1242:FF + cheat + description:Character 4 - Max FATE + code:7E1243:FF + cheat + description:Character 5 - Max LEVEL + code:7E12CA:FF + cheat + description:Character 5 - Infinite HP + code:7E12CE:E7+7E12CF:03 + cheat + description:Character 5 - Max HP + code:7E12CC:E7+7E12CD:03 + cheat + description:Character 5 - Infinite AP + code:7E12D2:E7+7E12D3:03 + cheat + description:Character 5 - Max AP + code:7E12D0:E7+7E12D1:03 + cheat + description:Character 5 - Max Str + code:7E12D7:FF + cheat + description:Character 5 - Max Vigor + code:7E12D8:FF + cheat + description:Character 5 - Max Wisdom + code:7E12D9:FF + cheat + description:Character 5 - Max Agil + code:7E12DA:FF + cheat + description:Character 5 - Max MAG + code:7E12DB:FF + cheat + description:Character 5 - Max Luck + code:7E12DC:FF + cheat + description:Character 5 - Max ATK + code:7E12DD:E7+7E12DE:03 + cheat + description:Character 5 - Max DEF + code:7E12DF:E7+7E12E0:03 + cheat + description:Character 5 - Max INT + code:7E12E1:FF + cheat + description:Character 5 - Max ACT + code:7E12E2:FF + cheat + description:Character 5 - Max FATE + code:7E12E3:FF + cheat + description:Character 6 - Max LEVEL + code:7E136A:FF + cheat + description:Character 6 - Infinite HP + code:7E136E:E7+7E136F:03 + cheat + description:Character 6 - Max HP + code:7E136C:E7+7E136D:03 + cheat + description:Character 6 - Infinite AP + code:7E1372:E7+7E1373:03 + cheat + description:Character 6 - Max AP + code:7E1370:E7+7E1371:03 + cheat + description:Character 6 - Max Str + code:7E1377:FF + cheat + description:Character 6 - Max Vigor + code:7E1378:FF + cheat + description:Character 6 - Max Wisdom + code:7E1379:FF + cheat + description:Character 6 - Max Agil + code:7E137A:FF + cheat + description:Character 6 - Max MAG + code:7E137B:FF + cheat + description:Character 6 - Max Luck + code:7E137C:FF + cheat + description:Character 6 - Max ATK + code:7E137D:E7+7E137E:03 + cheat + description:Character 6 - Max DEF + code:7E137F:E7+7E1380:03 + cheat + description:Character 6 - Max INT + code:7E1381:FF + cheat + description:Character 6 - Max ACT + code:7E1382:FF + cheat + description:Character 6 - Max FATE + code:7E1383:FF + cheat + description:Character 7 - Max LEVEL + code:7E140A:FF + cheat + description:Character 7 - Infinite HP + code:7E140E:E7+7E140F:03 + cheat + description:Character 7 - Max HP + code:7E140C:E7+7E140D:03 + cheat + description:Character 7 - Infinite AP + code:7E1412:E7+7E1413:03 + cheat + description:Character 7 - Max AP + code:7E1410:E7+7E1411:03 + cheat + description:Character 7 - Max Str + code:7E1417:FF + cheat + description:Character 7 - Max Vigor + code:7E1418:FF + cheat + description:Character 7 - Max Wisdom + code:7E1419:FF + cheat + description:Character 7 - Max Agil + code:7E141A:FF + cheat + description:Character 7 - Max MAG + code:7E141B:FF + cheat + description:Character 7 - Max Luck + code:7E141C:FF + cheat + description:Character 7 - Max ATK + code:7E141D:E7+7E141E:03 + cheat + description:Character 7 - Max DEF + code:7E141F:E7+7E1420:03 + cheat + description:Character 7 - Max INT + code:7E1421:FF + cheat + description:Character 7 - Max ACT + code:7E1422:FF + cheat + description:Character 7 - Max FATE + code:7E1423:FF + cheat + description:Character 8 - Max LEVEL + code:7E14AA:FF + cheat + description:Character 8 - Infinite HP + code:7E14AE:E7+7E14AF:03 + cheat + description:Character 8 - Max HP + code:7E14AC:E7+7E14AD:03 + cheat + description:Character 8 - Infinite AP + code:7E14B2:E7+7E14B3:03 + cheat + description:Character 8 - Max AP + code:7E14B0:E7+7E14B1:03 + cheat + description:Character 8 - Max Str + code:7E14B7:FF + cheat + description:Character 8 - Max Vigor + code:7E14B8:FF + cheat + description:Character 8 - Max Wisdom + code:7E14B9:FF + cheat + description:Character 8 - Max Agil + code:7E14BA:FF + cheat + description:Character 8 - Max MAG + code:7E14BB:FF + cheat + description:Character 8 - Max Luck + code:7E14BC:FF + cheat + description:Character 8 - Max ATK + code:7E14BD:E7+7E14BE:03 + cheat + description:Character 8 - Max DEF + code:7E14BF:E7+7E14C0:03 + cheat + description:Character 8 - Max INT + code:7E14C1:FF + cheat + description:Character 8 - Max ACT + code:7E14C2:FF + cheat + description:Character 8 - Max FATE + code:7E14C3:FF + +cartridge sha256:fede9d4aec8c35ed11e2868c3c517bce53ee3e6af724085c92500e99e43e63de + title:Breath of Fire II (USA) + cheat + description:Infinite HP in battle + code:C9FA-EFA6 + cheat + description:Infinite AP In menu + code:8E64-EDAA + cheat + description:Infinite AP In battle + code:8BDA-8DDC + cheat + description:Main character is different + code:46DA-87D4+45DA-87D4+FDDA-87D4+F4DA-87D4+F0DA-87D4 + cheat + description:Start with 50 HP + code:74DA-8F64 + cheat + description:Start with 100 HP + code:10DA-8F64 + cheat + description:Start with 150 HP + code:B1DA-8F64 + cheat + description:Start with 250 HP + code:ECDA-8F64 + cheat + description:Start with 500 HP + code:DFDA-8FA4+E0DA-8F64 + cheat + description:Start with 750 HP + code:D4DA-8FA4+33DA-8F64 + cheat + description:Start with a lot of HP + code:FEDA-8FA4 + cheat + description:Start with 50 AP + code:74DA-8464 + cheat + description:Start with 100 AP + code:10DA-8464 + cheat + description:Start with 150 AP + code:B1DA-8464 + cheat + description:Start with 250 AP + code:ECDA-8464 + cheat + description:Start with 500 AP + code:DFDA-84A4+E0DA-8464 + cheat + description:Start with 750 AP + code:D4DA-84A4+33DA-8464 + cheat + description:Start with a lot of AP + code:FEDA-84A4 + cheat + description:Start with 0 strength + code:DDDA-8704 + cheat + description:Start with Mega strength + code:EEDA-8704 + cheat + description:Start with 0 stamina + code:DDDA-8764 + cheat + description:Start with Mega stamina + code:EEDA-8764 + cheat + description:Start with 0 agility + code:DDDA-87A4 + cheat + description:Start with Mega agility + code:EEDA-87A4 + cheat + description:Start with 0 wisdom + code:DDD3-84D4 + cheat + description:Start with Mega wisdom + code:EED3-84D4 + cheat + description:Start with 0 luck + code:DDD3-8404 + cheat + description:Start with Mega luck + code:EED3-8404 + cheat + description:Start with Mega EXP + code:EED3-87D4 + cheat + description:No random battles + code:7E12DC:00 + cheat + description:Infinite Fishing Rod power + code:7E128C:60 + cheat + description:Have all warp points + code:7E5670:FF+7E5671:FF+7E5672:FF+7E5673:FF + cheat + description:Have all Shamans + code:7E5695:FF + cheat + description:Infinite Shaman use + code:7E5696:00+7E5697:00+7E5698:00+7E5699:00+7E569A:00+7E569B:00 + cheat + description:Have all non-shop tenants + code:7E55EB:DE+7E55EC:7B+7E55ED:77+7E55EE:0B + cheat + description:Character 1 - No Status Effects + code:7E51E5:00 + cheat + description:Character 1 - Level 99 + code:7E51E7:63 + cheat + description:Character 1 - Infinite HP + code:7E51E8:0F+7E51E9:27 + cheat + description:Character 1 - Maximum HP + code:7E51EA:0F+7E51EB:27 + cheat + description:Character 1 - Infinite AP + code:7E51EC:0F+7E51ED:27 + cheat + description:Character 1 - Maximum AP + code:7E51EE:0F+7E51EF:27 + cheat + description:Character 1 - 255 Str + code:7E51F1:FF + cheat + description:Character 1 - 255 Stmna + code:7E51F2:FF + cheat + description:Character 1 - 255 Agil + code:7E51F3:FF + cheat + description:Character 1 - 9999 Off + code:7E5202:0F+7E5203:27 + cheat + description:Character 1 - 9999 Def + code:7E5204:0F+7E5205:27 + cheat + description:Character 1 - 9999 Vigor + code:7E5206:0F+7E5207:27 + cheat + description:Character 1 - 255 Temporary Wisdom + code:7E5208:FF + cheat + description:Character 1 - 255 Temporary Luck + code:7E5209:FF + cheat + description:Character 1 - 255 Permanant Wisdom (next time you change equipment) + code:7E520C:FF + cheat + description:Character 1 - 255 Permanant Luck (next time you change equipment) + code:7E520D:FF + cheat + description:Character 1 - Maximum Guts + code:7E520B:FF + cheat + description:Character 1 - 9999999 EXP + code:7E520E:7F+7E520F:96+7E5210:98 + cheat + description:Character 1 - Maximum Jewel color + code:7E520A:FF + cheat + description:Character 2 - No Status Effects + code:7E5225:00 + cheat + description:Character 2 - Level 99 + code:7E5227:63 + cheat + description:Character 2 - Infinite HP + code:7E5228:0F+7E5229:27 + cheat + description:Character 2 - Maximum HP + code:7E522A:0F+7E522B:27 + cheat + description:Character 2 - Infinite AP + code:7E522C:0F+7E522D:27 + cheat + description:Character 2 - Maximum AP + code:7E522E:0F+7E522F:27 + cheat + description:Character 2 - 255 Str + code:7E5231:FF + cheat + description:Character 2 - 255 Stmna + code:7E5232:FF + cheat + description:Character 2 - 255 Agil + code:7E5233:FF + cheat + description:Character 2 - 9999 Off + code:7E5242:0F+7E5243:27 + cheat + description:Character 2 - 9999 Def + code:7E5244:0F+7E5245:27 + cheat + description:Character 2 - 9999 Vigor + code:7E5246:0F+7E5247:27 + cheat + description:Character 2 - 255 Temporary Wisdom + code:7E5248:FF + cheat + description:Character 2 - 255 Temporary Luck + code:7E5249:FF + cheat + description:Character 2 - 255 Permanant Wisdom (next time you change equipment) + code:7E524C:FF + cheat + description:Character 2 - 255 Permanant Luck (next time you change equipment) + code:7E524D:FF + cheat + description:Character 2 - Maximum Guts + code:7E524B:FF + cheat + description:Character 2 - 9999999 EXP + code:7E524E:7F+7E524F:96+7E5250:98 + cheat + description:Character 2 - Maximum Jewel color + code:7E524A:FF + cheat + description:Character 3 - No Status Effects + code:7E5265:00 + cheat + description:Character 3 - Level 99 + code:7E5267:63 + cheat + description:Character 3 - Infinite HP + code:7E5268:0F+7E5269:27 + cheat + description:Character 3 - Maximum HP + code:7E526A:0F+7E526B:27 + cheat + description:Character 3 - Infinite AP + code:7E526C:0F+7E526D:27 + cheat + description:Character 3 - Maximum AP + code:7E526E:0F+7E526F:27 + cheat + description:Character 3 - 255 Str + code:7E5271:FF + cheat + description:Character 3 - 255 Stmna + code:7E5272:FF + cheat + description:Character 3 - 255 Agil + code:7E5273:FF + cheat + description:Character 3 - 9999 Off + code:7E5282:0F+7E5283:27 + cheat + description:Character 3 - 9999 Def + code:7E5284:0F+7E5285:27 + cheat + description:Character 3 - 9999 Vigor + code:7E5286:0F+7E5287:27 + cheat + description:Character 3 - 255 Temporary Wisdom + code:7E5288:FF + cheat + description:Character 3 - 255 Temporary Luck + code:7E5289:FF + cheat + description:Character 3 - 255 Permanant Wisdom (next time you change equipment) + code:7E528C:FF + cheat + description:Character 3 - 255 Permanant Luck (next time you change equipment) + code:7E528D:FF + cheat + description:Character 3 - Maximum Guts + code:7E528B:FF + cheat + description:Character 3 - 9999999 EXP + code:7E528E:7F+7E528F:96+7E5290:98 + cheat + description:Character 3 - Maximum Jewel color + code:7E528A:FF + cheat + description:Character 4 - No Status Effects + code:7E52A5:00 + cheat + description:Character 4 - Level 99 + code:7E52A7:63 + cheat + description:Character 4 - Infinite HP + code:7E52A8:0F+7E52A9:27 + cheat + description:Character 4 - Maximum HP + code:7E52AA:0F+7E52AB:27 + cheat + description:Character 4 - Infinite AP + code:7E52AC:0F+7E52AD:27 + cheat + description:Character 4 - Maximum AP + code:7E52AE:0F+7E52AF:27 + cheat + description:Character 4 - 255 Str + code:7E52B1:FF + cheat + description:Character 4 - 255 Stmna + code:7E52B2:FF + cheat + description:Character 4 - 255 Agil + code:7E52B3:FF + cheat + description:Character 4 - 9999 Off + code:7E52C2:0F+7E52C3:27 + cheat + description:Character 4 - 9999 Def + code:7E52C4:0F+7E52C5:27 + cheat + description:Character 4 - 9999 Vigor + code:7E52C6:0F+7E52C7:27 + cheat + description:Character 4 - 255 Temporary Wisdom + code:7E52C8:FF + cheat + description:Character 4 - 255 Temporary Luck + code:7E52C9:FF + cheat + description:Character 4 - 255 Permanant Wisdom (next time you change equipment) + code:7E52CC:FF + cheat + description:Character 4 - 255 Permanant Luck (next time you change equipment) + code:7E52CD:FF + cheat + description:Character 4 - Maximum Guts + code:7E52CB:FF + cheat + description:Character 4 - 9999999 EXP + code:7E52CE:7F+7E52CF:96+7E52D0:98 + cheat + description:Character 4 - Maximum Jewel color + code:7E52CA:FF + +cartridge sha256:0a07808939e77d8c4a13a6ec7bbc008ee758cd209f8404411bf15d225453beee + title:BS Zelda no Densetsu - Dai-3-wa (Japan) (BS) + cheat + description:Disable the 57 minute time limit + code:3CDD-7F5D+3CDD-7F8D+6DDD-7FED + +cartridge sha256:811cbc3287c0959e8eb242e817684d36de664ebebc5873a1fa9958693857c438 + title:Bubsy in Claws Encounters of the Furred Kind (USA) + cheat + description:Infinite lives + code:DDB1-175C + cheat + description:Infinite time + code:DDB4-3404 + cheat + description:Numbered t-shirts worth one more + code:766C-1766 + cheat + description:Bogus jump + code:946B-1D8B + cheat + description:Super-jump + code:716B-1D8B + cheat + description:Mega-jump + code:436B-1D8B + cheat + description:Each yarn ball worth 0 + code:DD60-1FD6 + cheat + description:Each yarn ball worth 5 + code:D960-1FD6 + cheat + description:Each yarn ball worth 10 + code:FD60-1FD6 + cheat + description:Crate of yarn holds 0 instead of 25 + code:DD69-4F6C + cheat + description:Crate of yarn holds 50 + code:9D69-4F6C + cheat + description:Crate of yarn holds 75 + code:5969-4F6C + cheat + description:Crate of yarn holds 99 + code:BB69-4F6C + cheat + description:Start with 1 life + code:DD34-4D6D + cheat + description:Start with 5 lives + code:D034-4D6D + cheat + description:Start with 25 lives + code:4034-4D6D + cheat + description:Start with 50 lives + code:9D34-4D6D + cheat + description:Start with 75 lives + code:5934-4D6D + cheat + description:Start on chapter 2 + code:DF6D-472A + cheat + description:Start on chapter 3 + code:D46D-472A + cheat + description:Start on chapter 4 + code:D76D-472A + cheat + description:Start on chapter 5 + code:D06D-472A + cheat + description:Start on chapter 6 + code:D96D-472A + cheat + description:Start on chapter 7 + code:D16D-472A + cheat + description:Start on chapter 8 + code:D66D-472A + cheat + description:Start on chapter 9 + code:DC6D-472A + cheat + description:Start on chapter 10 + code:DA6D-472A + cheat + description:Start on chapter 11 + code:D26D-472A + cheat + description:Start on chapter 12 + code:D36D-472A + cheat + description:Start on chapter 13 + code:DE6D-472A + cheat + description:Start on chapter 14 + code:FD6D-472A + cheat + description:Start on Chapter 15 + code:FF6D-472A + cheat + description:Start on Chapter 16 + code:F46D-472A + +cartridge sha256:2357d344af77d25dda030520ce203045fd9060f83e3b9609a228dba859d9017b + title:Bubsy II (USA) + cheat + description:Invincibility + code:62E5-5F0F + cheat + description:Infinite health + code:8FD5-EDD4 + cheat + description:Infinite lives + code:C2D8-7DAF + cheat + description:Infinite time in most main levels + code:C217-8DD7+C21F-87A7 + cheat + description:Infinite time in some bonus levels + code:C25C-740D + cheat + description:Infinite Warp Holes + code:C2DE-54D0 + cheat + description:Infinite Diving Suits + code:C212-57AD + cheat + description:Infinite Smart Bombs + code:C271-7DD0 + cheat + description:Infinite ammo for Nerf Gun + code:C247-5465 + cheat + description:Infinite health (alt) + code:7E1188:04 + cheat + description:Infinite lives (alt) + code:7E3422:09 + +cartridge sha256:49020695a017acc3dfadea97a60e28609e583571f69c5abeb3c6b1c2db8113fa + title:Bugs Bunny - Rabbit Rampage (USA) + cheat + description:Invincibility + code:2D6A-17AF + cheat + description:Infinite energy + code:C28C-4FAF + cheat + description:Infinite lives + code:DDA3-3D07 + cheat + description:Infinite lives (alt) + code:C2A3-3DA7 + cheat + description:Take minimal damage + code:A38C-4FAF + cheat + description:Full energy from carrots + code:DD88-476F + cheat + description:Moon jumping Bugs + code:F0B4-1404 + cheat + description:Super-jumping Bugs + code:0DB4-1404+E0B7-1DD4 + cheat + description:Start and continue with 10 lives + code:DC60-CD0D + cheat + description:Start and continue with 2 lives + code:D460-CD0D + +cartridge sha256:d6f6c30732dae8d00cd83628c3156acbdf26f99df701f779522e21de74dae5fe + title:Bust-A-Move (USA) + cheat + description:Infinite continues + code:C281-DFE2 + cheat + description:Infinite time to shoot each ball + code:3C38-A764 + cheat + description:Always get max bonus in shooting rounds + code:3C83-D467 + cheat + description:Shot guide is always on (new 1P game) + code:338B-0DA4 + cheat + description:Shot guide is always on (password game) + code:338D-07A4 + cheat + description:Shot guide is always on ("challenge record" mode) + code:333E-D721 + +cartridge sha256:2a117951adcfbc4298763673a834d502c3f7a3964db1e59650f113c07bb831fb + title:Captain America and the Avengers (USA) + cheat + description:Invincibility - both players + code:1D38-CFA1+6DAA-CD00+82A6-3D60 + cheat + description:Infinite lives - both players + code:C283-34A0 + cheat + description:Invincibility - P1 + code:7E16A8:20 + cheat + description:Invincibility - P2 + code:7E16A9:63 + cheat + description:Infinite health - P1 + code:7E0226:63 + cheat + description:Infinite health - P2 + code:7E0227:63 + cheat + description:Infinite lives - P1 + code:7E0229:09 + cheat + description:Infinite lives - P2 + code:7E022A:09 + +cartridge sha256:d9b7f9356be0780f0037093a86ef8450f15e569cbd3680073d1cd345dfadb709 + title:Captain Commando (USA) + cheat + description:Invincibility - p1 + code:CB4E-7FD4+D04E-7F04+B24E-7F64 + cheat + description:Hit anywhere (throws are disabled) + code:6DF1-846D+6DF9-74DF+6DFA-7D0F+95F9-740F + cheat + description:One hit kills - Both players + code:76F4-57DF+3BF4-570F+6DF4-576F + cheat + description:Invincibility - P1 (alt) + code:7E0404:03 + cheat + description:Infinite health - P1 + code:7E0895:32 + cheat + description:Infinite health - P2 + code:7E0893:32 + cheat + description:9 lives - P1 + code:7E0B15:09 + cheat + description:9 lives - P2 + code:7E0B13:09 + cheat + description:9 continues + code:7E1D5A:39 + +cartridge sha256:8784614896e2b3e8d98c8166613ca5d2329643795a4dc107791c58c6c51e1268 + title:Captain Novolin (USA) (En,Fr,Es) + cheat + description:Invincibility + code:7E0C02:29 + cheat + description:Infinite health + code:7E0BDA:04 + cheat + description:Infinite time + code:7E16F2:00 + +cartridge sha256:be2bdb03549665136cc91173ac538b41b3085e0f1f6b02d6567d174b5b78e435 + title:Caravan Shooting Collection (Japan) + cheat + description:Hector 87 - Infinite health + code:7E00E5:10 + cheat + description:Hector 87 - Infinite lives + code:7E00E4:02 + cheat + description:Star Force - Invincibility + code:7E09CA:01 + cheat + description:Star Force - Always have powered-up weapon + code:7E099E:01 + cheat + description:Star Force - Infinite lives + code:7E094D:02 + cheat + description:Star Force - No enemies (disable before reaching the boss) + code:7E0963:05 + cheat + description:Star Soldier - Invincibility + code:7E0086:39 + cheat + description:Star Soldier - Infinite lives + code:7E062F:02 + cheat + description:Star Soldier - Rapid fire + code:7E0630:00 + cheat + description:Star Soldier - Ship is always blue + code:7E0087:00 + cheat + description:Star Soldier - No enemies except bosses + code:7E062E:00 + +cartridge sha256:ee5fc27dd19a2ecb3c3c7c73d558a18ffd5ff365710c18b88150e277f08d587e + title:Carrier Aces (USA) + cheat + description:Invincibility (works for dogfights and ship fire) + code:DDED-670F+6DEE-64DD + cheat + description:Infinite fuel + code:C2B3-6F64 + cheat + description:Infinite rockets + code:3CC9-D764 + +cartridge sha256:b9b982cd8f91c51089d49b550f11882b1ee785ebddcb7355cfc465916d61a042 + title:Casper (USA) + cheat + description:Infinite lives + code:C225-1071 + cheat + description:Infinite health + code:C221-1981 + cheat + description:Have all items and 5 lives after you leave the first room + code:2DAC-CD44 + +cartridge sha256:367725a149a471411e4f72ad77603b61fb101c9cab4521be5647e13708cc97ba + title:Castlevania - Dracula X (USA) + cheat + description:Invincibility + code:2D69-CD9D + cheat + description:Invincibility after one hit + code:C969-CD2D + cheat + description:Infinite health + code:C96D-17FF + cheat + description:Infinite lives + code:C9AF-47A7 + cheat + description:All hearts worth 99 + code:2D25-1FD3+DD25-1F03 + cheat + description:Keep sub-weapon after dying + code:C9A4-47D7 + cheat + description:Keep sub-weapon after continue + code:C985-17DF + cheat + description:Item Crash doesn't use hearts + code:C9A6-3D94 + cheat + description:Hit anywhere + code:DD20-34D3+DD24-3403 + cheat + description:Small hearts worth 0 + code:DD29-1763 + cheat + description:Small hearts worth 10 + code:FD29-1763 + cheat + description:Small hearts worth 25 + code:4929-1763 + cheat + description:No Invincibility after getting hit + code:DD6F-CFBF + cheat + description:More invincibility after getting hit + code:EE6F-CFBF + cheat + description:Super jump + code:EB87-C7BD + cheat + description:Super-Duper jump + code:E687-C7BD + cheat + description:Mega-jump + code:E587-C7BC + cheat + description:Have the Axe + code:DFDC-F276 + cheat + description:Have the Cross + code:D4DC-F276 + cheat + description:Have the Holy Water + code:D7DC-F276 + cheat + description:Have the Knife + code:D0DC-F276 + cheat + description:Have the Clock + code:D9DC-F276 + cheat + description:Have the Key + code:D1DC-F276 + cheat + description:Start with half energy + code:4D21-1707 + cheat + description:Start with 1/4 energy + code:F421-1707 + cheat + description:Start with 3/4 energy + code:7D21-1707 + cheat + description:Start with 99 hearts + code:6D81-170F + cheat + description:Start with 50 hearts + code:9D81-170F + cheat + description:Start with 25 hearts + code:4981-170F + cheat + description:Start with 1 life + code:DD85-1D6F + cheat + description:Start with 10 lives + code:DB85-1D6F + cheat + description:Start with 25 lives + code:4085-1D6F + cheat + description:Start with 50 lives + code:0B85-1D6F + cheat + description:Start with 99 lives + code:BB85-1D6F + cheat + description:Start with 25 hearts after you die + code:49A4-44D7 + cheat + description:Start with 50 hearts after you die + code:9DA4-44D7 + cheat + description:Start with 99 hearts after you die + code:BBA4-44D7 + cheat + description:Start on level 2 + code:DFD5-F376 + cheat + description:Start on level 3 + code:D4D5-F376 + cheat + description:Start on level 4 + code:D7D5-F376 + cheat + description:Start on level 5 + code:D0D5-F376 + cheat + description:Start on level 6 + code:D9D5-F376 + cheat + description:Start on level 7 + code:D1D5-F376 + +cartridge sha256:aa69d4e19c2eb206fe88eba65994c830256c220e5506f59824aefa0a75dd44d5 + title:Chavez (USA) + cheat + description:Infinite time + code:7E1F93:15 + +cartridge sha256:ee0e51d922d1cf8abe3dfc6b0d84a988a6635dc96b2a96962007c41aaa542774 + title:Chessmaster, The (USA) + cheat + description:White player's timer is stopped + code:C9C7-D76F + cheat + description:Black player's timer is stopped + code:C9C9-DFDF + cheat + description:Timers count 2x as slow + code:56C4-D46F + cheat + description:Timers count 3x times as slow + code:80C4-D46F + cheat + description:Timers count 2x as fast + code:F3C4-D46F + cheat + description:Timers count 3x times as fast + code:F0C4-D46F + +cartridge sha256:c7e7df8932bf0056aa530f3dc3c913c1171a359af4c197094c2b972946dc6051 + title:Chester Cheetah - Too Cool to Fool (USA) + cheat + description:Invincibility (blinking) (you may freeze if you get the guitar and fall in water) + code:3C60-04D9 + cheat + description:Infinite life points + code:3CBF-0D69 + cheat + description:Infinite credits + code:A26F-04D4 + cheat + description:Badges worth 5 + code:D965-D7DB + cheat + description:Badges worth 25 + code:4965-D7DB + cheat + description:Badges worth 50 + code:9D65-D7DB + cheat + description:Start with 2 life points + code:D469-DFD9 + cheat + description:Start with 0 life points + code:DD69-DFD9 + +cartridge sha256:21a2aa488cb8140ca318f7d1f513103d14e758181aa336a594097d32ba0a7587 + title:Chester Cheetah - Wild Wild Quest (USA) + cheat + description:Invincibility (once you eat a bag of Cheetos) + code:C3CC-6D07 + cheat + description:Infinite Cheetos bags (once you collect one) + code:C282-DFD4 + cheat + description:Infinite time + code:C2B2-A4AD + cheat + description:Infinte lives + code:C2BC-D7AF + +cartridge sha256:9a064b67f522b75b82d0857519c0e33b4dbbe494c2ef79a44fdc913d605d0b26 + title:Choplifter III - Rescue & Survive (USA) + cheat + description:Have all weapons and infinte ammo + code:DD67-CDA7+DD60-CF67 + cheat + description:Infinite secondary weapons + code:3C60-34D7 + cheat + description:Infinite choppers + code:C26D-1767 + cheat + description:Chopper can carry 30 hostages + code:F3C7-3D53+F3C1-1F5E + cheat + description:Invincibility + code:7E0CEB:5A + +cartridge sha256:224572832b988f31a81c907f751f0292f5702a3acea5866ce6742387c7c6239d + title:Choujikuu Yousai Macross - Scrambled Valkyrie (Japan) + cheat + description:Infinite health + code:C268-4F64+C269-47A4 + cheat + description:Infinite absorb charge + code:C2B2-C4D1 + cheat + description:Hit anywhere + code:DD6B-3FD7+DD65-3467+DD66-34D7 + cheat + description:Invincibility + code:7E0A90:FF + cheat + description:Infinite continues + code:7E02AA:09 + +cartridge sha256:06d1c2b06b716052c5596aaa0c2e5632a027fee1a9a28439e509f813c30829a9 + title:Chrono Trigger (USA) + cheat + description:Use "organize" to get 90 of all items + code:B6C6-E76C+DDCB-E7DC+9CCB-E76C + cheat + description:Maxed out abilities for all characters + code:65EB-E4A9 + cheat + description:Every attack causes 9999 damage + code:B323-7405 + cheat + description:Can open sealed chests + code:6D1C-770F + cheat + description:Start with a higher max HP + code:EEDD-7F5D + cheat + description:Start with a higher max MP + code:63DD-745D + cheat + description:Start with max power + code:BDDD-74ED + cheat + description:Start with max stamina + code:BDDD-777D + cheat + description:Start with max speed + code:BDDD-775D + cheat + description:Start with max magic + code:BDDD-778D + cheat + description:Start with max hit ratio + code:BDDD-77ED + cheat + description:Start with max evade + code:BDDF-7D7D + cheat + description:Start with max magic defense + code:BDDF-7D5D + cheat + description:Position 1 - Infinite health + code:7E5E30:E7+7E5E31:03 + cheat + description:Position 1 - Infinite Magic + code:7E5E34:63 + cheat + description:Position 1 - Attack bar always full + code:7EAFAB:00 + cheat + description:Position 2 - Infinite health + code:7E5EB0:E7+7E5EB1:03 + cheat + description:Position 2 - Infinite Magic + code:7E5EB4:63 + cheat + description:Position 2 - Attack bar always full + code:7EAFAC:00 + cheat + description:Position 3 - Infinite health + code:7E5F30:E7+7E5F31:03 + cheat + description:Position 3 - Infinite Magic + code:7E5F34:63 + cheat + description:Position 3 - Attack bar always full + code:7EAFAD:00 + cheat + description:Infinite Speed Boosts + code:7E009A:03 + cheat + description:Instantly enable next Speed Boost + code:7E00BA:00 + +cartridge sha256:63ab79e86ea13e2cf9bb67aec971febb68450db9865b00b5f412610653822393 + title:Chuck Rock (USA) + cheat + description:Infinite health + code:C9A1-A70D + cheat + description:Infinite lives + code:C9AB-AF0D + cheat + description:Jump higher + code:70C9-A7DD + cheat + description:Super-jump + code:49C9-A7DD + cheat + description:Mega-jump + code:F5C9-A7DD + cheat + description:Invincibility + code:7E0BAA:25 + +cartridge sha256:de2d5a952096c5f50368b9270d342aa6e7a39007ffbec27117e182e30ef4cf32 + title:Civilization (USA) + cheat + description:Get a new skill every turn + code:DD30-74A4 + cheat + description:Have 42.0 moves until you specify no orders + code:CB28-5DA4+5328-5FD4 + cheat + description:Start with more money + code:BB04-EF74+BB04-EF54 + cheat + description:Start with a lot more money + code:EE04-EF74+EE04-EF54 + cheat + description:Infinite time + code:7E75D7:00 + cheat + description:Max income + code:7E7630:FF + +cartridge sha256:8b7525b2aa30cbea9e3deee601dd26e0100b8169c1948f19866be15cae0ac00d + title:Clay Fighter (USA) + cheat + description:Infinite health - P1 + code:C20B-7916+C256-E536 + cheat + description:Enable Blob's Bomb move (away, away + down, down, towards + down, towards, punch) + code:6280-DD6F + cheat + description:Always fight Bad Mr. Frosty after 1st match + code:DD4A-8548+DD9C-E53E + cheat + description:Always fight Taffy after 1st match + code:DD4A-8548+DF9C-E53E + cheat + description:Always fight Tiny after 1st match + code:DD4A-8548+D49C-E53E + cheat + description:Always fight The Blob after 1st match + code:DD4A-8548+D79C-E53E + cheat + description:Always fight Blue Suede Goo after 1st match + code:DD4A-8548+D09C-E53E + cheat + description:Always fight Ickybod Clay after 1st match + code:DD4A-8548+D99C-E53E + cheat + description:Always fight Helga after 1st match + code:DD4A-8548+D19C-E53E + cheat + description:Always fight Bonker after 1st match + code:DD4A-8548+D59C-E53E + cheat + description:Always fight N. Boss after 1st match + code:DD4A-8548+D69C-E53E + cheat + description:Start with 1/6 health - 1st round + code:FDF7-E5CE + cheat + description:Start with 1/3 health - 1st round + code:4DF7-E5CE + cheat + description:Start with 1/2 health - 1st round + code:7DF7-E5CE + cheat + description:Start with 2/3 health - 1st round + code:0DF7-E5CE + cheat + description:Start with 5/6 health - 1st round + code:9DF7-E5CE + cheat + description:Start with 1/6 health - 2nd and later rounds + code:FD4A-E01C + cheat + description:Start with 1/3 health - 2nd and later rounds + code:4D4A-E01C + cheat + description:Start with 1/2 health - 2nd and later rounds + code:7D4A-E01C + cheat + description:Start with 2/3 health - 2nd and later rounds + code:0D4A-E01C + cheat + description:Start with 5/6 health - 2nd and later rounds + code:9D4A-E01C + cheat + description:Bad Mr. Frosty's Brutal Punches do more damage + code:7D46-E1C2+7D46-E132+7D46-E542+7D46-E512+7D46-E5C2 + cheat + description:Bad Mr. Frosty's Medium Punches do more damage + code:7D46-E532+7D4B-E042+7D4B-E012+7D4B-E0C2+7D4B-E032 + cheat + description:Bad Mr. Frosty's Quick Punches do more damage + code:7D4B-E942+7D4B-E912+7D4B-E9C2+7D4B-E932+7D4B-E142 + cheat + description:Bad Mr. Frosty's Brutal Kicks do more damage + code:7D4B-E112+7D4B-E1C2+7D4B-E132+7D4B-E542+7D4B-E512 + cheat + description:Bad Mr. Frosty's Medium Kicks do more damage + code:7D4B-E5C2+7D4B-E532+7D4C-E042+7D4C-E012+7D4C-E0C2 + cheat + description:Bad Mr. Frosty's Quick Kicks do more damage + code:7D4C-E032+7D4C-E942+7D4C-E912+7D4C-E9C2+7D4C-E932 + cheat + description:Bad Mr. Frosty's Snow Ball (all punches) does more damage + code:7D4C-E142 + cheat + description:Taffy's Brutal Punches do more damage + code:7D48-E0C2+7D48-E032+7D48-E942+7D48-E912+7D48-E9C2 + cheat + description:Taffy's Medium Punches do more damage + code:7D48-E932+7D48-E142+7D48-E112+7D48-E1C2+7D48-E132 + cheat + description:Taffy's Quick Punches do more damage + code:7D48-E542+7D48-E512+7D48-E5C2+7D48-E532+7D4A-E042 + cheat + description:Taffy's Brutal Kicks do more damage + code:7D4A-E012+7D4A-E0C2+7D4A-E032+7D4A-E942+7D4A-E912 + cheat + description:Taffy's Medium kick does more damage + code:7D4A-E9C2+7D4A-E932+7D4A-E142+7D4A-E112+7D4A-E1C2 + cheat + description:Taffy's Quick Kicks do more damage (not in crouch) + code:7D4A-E132+7D4A-E542+7D4A-7513+7D4A-E5C2+7D4A-E532 + cheat + description:Taffy's Whack (all punches) does more damage + code:7D42-E912 + cheat + description:Taffy's Whack (all kicks) does more damage + code:7D42-E9C2 + cheat + description:Tiny's Brutal Punches do more damage + code:7D42-E1C2+7D42-E132+7D42-E542+7D42-E512+7D42-E5C2 + cheat + description:Tiny's Medium Punches do more damage + code:7D42-E532+7D43-E042+7D43-E012+7D43-E0C2+7D43-E032 + cheat + description:Tiny's Quick Punches do more damage + code:7D43-E942+7D43-E912+7D43-E9C2+7D43-E932+7D43-E142 + cheat + description:Tiny's Brutal Kicks do more damage + code:7D43-E112+7D43-E1C2+7D43-E132+7D43-E542+7D43-E512 + cheat + description:Tiny's Medium Kicks do more damage + code:7D43-E5C2+7D43-E532+7D4E-E042+7D4E-E012+7D4E-E0C2 + cheat + description:Tiny's Quick Kicks do more damage + code:7D4E-E032+7D4E-E942+7D4E-E912+7D4E-E9C2+7D4E-E932 + cheat + description:Tiny's Medicine Ball Does more damage + code:7D4E-E142 + cheat + description:Tiny's Sucker Punch does more damage + code:7D4E-E512 + cheat + description:Blob's Brutal Punches do more damage + code:7D4D-70C3+7D4D-7033+7D4D-7943+7D4D-7913+7D4D-79C3 + cheat + description:Blob's Medium Punches do more damage + code:7D4D-7933+7D4D-7143+7D4D-7113+7D4D-71C3+7D4D-7133 + cheat + description:Blob's Quick Punches do more damage + code:7D4D-7543+7D4D-7513+7D4D-75C3+7D4D-7533+7D4F-7043 + cheat + description:Blob's Brutal kick does more damage + code:7D4F-7013+7D4F-70C3+7D4F-7033+7D4F-7943+7D4F-7913 + cheat + description:Blob's Medium Kicks do more damage + code:7D4F-79C3+7D4F-7933+7D4F-7143+7D4F-7113+7D4F-71C3 + cheat + description:Blob's Quick Kicks do more damage + code:7D4F-7133+7D4F-7543+7D4F-7513+7D4F-75C3+7D4F-7533 + cheat + description:Blue Suede Goo's Brutal Punches do more damage + code:7D44-71C3+7D44-7133+7D44-7543+7D44-7513+7D44-75C3 + cheat + description:Blue Suede Goo's Medium Punches do more damage + code:7D44-7533+7D47-7043+7D47-7013+7D47-70C3+7D47-7033 + cheat + description:Blue Suede Goo's Quick Punches do more damage + code:7D47-7943+7D47-7913+7D47-79C3+7D47-7933+7D47-7143 + cheat + description:Blue Suede Goo's Brutal Kicks do more damage + code:7D47-7113+7D47-71C3+7D47-7133+7D47-7543+7D47-7513 + cheat + description:Blue Suede Goo's Medium Kicks do more damage + code:7D47-75C3+7D47-7533+7D40-7043+7D40-7013+7D40-70C3 + cheat + description:Blue Suede Goo's Quick Kicks do more damage + code:7D40-7033+7D40-7943+7D40-7913+7D40-79C3+7D40-7933 + cheat + description:Ickybod Clay's Brutal Punches do more damage + code:7D49-70C3+7D49-7033+7D49-7943+7D49-7913+7D49-79C3 + cheat + description:Ickybod Clay's Medium Punches do more damage + code:7D49-7933+7D49-7143+7D49-7113+7D49-71C3+7D49-7133 + cheat + description:Ickybod Clay's Quick Punches do more damage + code:7D49-7543+7D49-7513+7D49-75C3+7D49-7533+7D41-7043 + cheat + description:Ickybod Clay's Brutal Kicks do more damage + code:7D41-7013+7D41-70C3+7D41-7033+7D41-7943+7D41-7913 + cheat + description:Ickybod Clay's Medium Kicks do more damage + code:7D41-79C3+7D41-7933+7D41-7143+7D41-7113+7D41-71C3 + cheat + description:Ickybod Clay's Quick Kicks do more damage + code:7D41-7133+7D41-7543+7D41-7513+7D41-75C3+7D41-7533 + cheat + description:Ickybod Clay's Ecto Punch does more damage + code:7D45-7013 + cheat + description:Helga's Brutal Punches do more damage + code:7D45-71C3+7D45-7133+7D45-7543+7D45-7513+7D45-75C3 + cheat + description:Helga's Medium Punches do more damage + code:7D45-7533+7D46-7043+7D46-7013+7D46-70C3+7D46-7033 + cheat + description:Helga's Quick Punches do more damage + code:7D46-7943+7D46-7913+7D46-79C3+7D46-7933+7D46-7143 + cheat + description:Helga's Brutal Kicks do more damage + code:7D46-7113+7D46-71C3+7D46-7133+7D46-7543+7D46-7513 + cheat + description:Helga's Medium Kicks do more damage + code:7D46-75C3+7D46-7533+7D4B-7043+7D4B-7013+7D4B-70C3 + cheat + description:Helga's Quick Kicks do more damage (not far away) + code:7D46-5033+7D4B-7943+7D4B-7913+7D4B-79C3+7D4B-7933 + cheat + description:Helga's Viking Ram does more damage + code:7D4B-71C3 + cheat + description:Bonker's Brutal Punches do more damage + code:7D4C-70C3+7D4C-7033+7D4C-7943+7D4C-7913+7D4C-79C3 + cheat + description:Bonker's Medium Punches do more damage + code:7D4C-7933+7D4C-7143+7D4C-7113+7D4C-71C3+7D4C-7133 + cheat + description:Bonker's Quick Punches do more damage + code:7D4C-7543+7D4C-7513+7D4C-75C3+7D4C-7533+7D48-7043 + cheat + description:Bonker's Brutal Kicks do more damage + code:7D48-7013+7D48-70C3+7D48-7033+7D48-7943+7D48-7913 + cheat + description:Bonker's Medium Kicks do more damage + code:7D48-79C3+7D48-7933+7D48-7143+7D48-7113+7D48-71C3 + cheat + description:Bonker's Quick Kicks do more damage + code:7D48-7133+7D48-7543+7D48-7513+7D48-75C3+7D48-7533 + cheat + description:Bonker's Cutting Cartwheel does more damage + code:7D4A-7043 + +cartridge sha256:2d40c86bc19d85555bf2672acf515b04dbf56a6a59b29ad503e672310b0fae3b + title:Clay Fighter 2 - Judgment Clay (USA) + cheat + description:Select more speed in options + code:4D08-E4A1 + cheat + description:Select more difficulty in options + code:DB0B-E4D1 + cheat + description:Both players jump off the screen + code:8F59-EDA7 + cheat + description:Infinite health and time + code:CB51-7D64+6251-7F04+4651-7F64+F651-7FA4 + cheat + description:Blob - Blob spit kills + code:EE0C-77E9 + cheat + description:Blob - Buzz saw kills + code:EE0E-7479 + cheat + description:Blob - Rocket-anvil attack kills + code:EE09-5789 + cheat + description:Hoppy - Spinning carrot kills + code:EEB0-5D7C + cheat + description:Hoppy - Spin kick towards (special move) kills + code:EEBB-5F8C + cheat + description:Octo - Brutal cartwheel kills (when close) + code:EE1C-5785 + cheat + description:Octo - Ground spin kills + code:EE15-8DE5 + +cartridge sha256:1d19e7fbe32eb26181c95fcbb028a5d64797ab65b86568eb059c60b8acf0d702 + title:Claymates (USA) (Sample) + cheat + description:Invincibility + code:C2D4-8F50 + cheat + description:Infinite time + code:C216-E779 + cheat + description:Multi-jump (tap jump button) + code:89DA-87E9 + cheat + description:Infinite lives + code:C218-8479 + +cartridge sha256:e5980b990605a9c91fa89101c440b2ec9993329296ba09a9538042d724a080fb + title:Cliffhanger (USA) + cheat + description:Invincibility + code:ED60-1761 + cheat + description:Infinite health + code:C28E-44A9 + cheat + description:Infinite ammo + code:C2CD-34A5 + cheat + description:Infinite lives + code:3C8B-1D69 + cheat + description:Hit anywhere + code:DD8F-CF60 + cheat + description:One hit kills on normal enemies + code:CBBC-3F6B+DFBC-3FAB + cheat + description:Stop snow avalanche (run into it) + code:1882-4D69 + +cartridge sha256:03f6c69aef92d36b5ea25a6023368da0e1da9fa160e8316ebd533d4f358ffacf + title:Clue (USA) + cheat + description:Always roll a 1 + code:CBBC-0D07+3CBC-0DA7+DDBC-0D67 + cheat + description:Always roll a 2 + code:CBBC-0D07+3CBC-0DA7+DFBC-0D67 + cheat + description:Always roll a 3 + code:CBBC-0D07+3CBC-0DA7+D4BC-0D67 + cheat + description:Always roll a 4 + code:CBBC-0D07+3CBC-0DA7+D7BC-0D67 + cheat + description:Always roll a 5 + code:CBBC-0D07+3CBC-0DA7+D0BC-0D67 + cheat + description:Always roll a 6 + code:CBBC-0D07+3CBC-0DA7+D9BC-0D67 + cheat + description:Allow no interrogations instead of 2 + code:BDBA-D464 + cheat + description:Allow only 1 interrogation + code:DFBA-D4D4 + cheat + description:Allow 3 interrogations + code:D7BA-D4D4 + cheat + description:Allow 4 interrogations + code:D0BA-D4D4 + cheat + description:Allow 5 interrogations + code:D9BA-D4D4 + cheat + description:Infinite interrogations + code:8B83-070F + +cartridge sha256:5536cea2da39f2572abe3b0fcf71f8fcd981376b470b174969772aae4a7a1845 + title:College Football USA '97 - The Road to New Orleans (USA) + cheat + description:Always 1st down + code:7E1836:05 + cheat + description:Infinite time + code:7E1828:FF + cheat + description:Have 50 points - P1 + code:7FB140:32+7FB726:32 + cheat + description:Have 50 time outs - P1 + code:7FB1C7:32 + +cartridge sha256:c88a882ad72dfa07a9b1eb8a2183aa10057d60877a02edf90cf2cd8c78abe65e + title:Combatribes, The (USA) + cheat + description:Invincibility - both players + code:2DB1-A7D4 + cheat + description:Infinite health - both players + code:3CB5-6F64+CBB5-6FA4+A6B5-64D4+62B5-6464 + cheat + description:Infinite credits + code:A2B3-A404 + cheat + description:Hit anywhere - P1 + code:3DBB-076D+70BC-0D6D+DDBB-07AD+DDBC-0DDD+EDBC-0D0D + cheat + description:One hit kills - both players + code:3DA3-64AF+DDA3-67DF+DDA3-670F+40AE-6FAF + cheat + description:Invincibility - P1 + code:7E1934:01 + cheat + description:Infinite health - P1 + code:7E1794:C8 + cheat + description:Infinite health - P2 + code:7E1796:C8 + cheat + description:Infinite credits (alt) + code:7E1564:09 + cheat + description:Unlock all characters in vs mode + code:7E1EE7:10 + +cartridge sha256:26e09f5bc2bde28d57aeca0bf5be7f7fb8e3b3887af975bcbf2e6f29b07df56f + title:Congo's Caper (USA) + cheat + description:Infinite lives + code:DDEC-CF6D + cheat + description:Stay as Super Congo (you may change if you walk on spikes) + code:CB69-34D7 + cheat + description:1 life after continue + code:DDB0-44D4 + cheat + description:6 lives after continue + code:D9B0-44D4 + cheat + description:9 lives after continue + code:D6B0-44D4 + cheat + description:1 ruby turns you into Super Congo + code:CBB2-340D+D4B2-346D + cheat + description:Start as Super Congo + code:64B9-4FD4 + cheat + description:Start with 1 life + code:DDAC-4F09 + cheat + description:Start with 6 lives + code:D9AC-4F09 + cheat + description:Start with 9 lives + code:D6AC-4F09 + +cartridge sha256:a93ea87fc835c530b5135c5294433d15eef6dbf656144b387e89ac19cf864996 + title:Contra III - The Alien Wars (USA) + cheat + description:Invincibility (top-view levels) + code:8961-6F08 + cheat + description:Invincibility (side-view levels) - P1 + code:89B3-6F01+89C0-6D09 + cheat + description:Invincibility (side-view levels) - P2 + code:89C5-6FD9+89B6-AFA1 + cheat + description:Infinite continues + code:C2CA-0F04 + cheat + description:Infinite lives (side-view levels) + code:22BB-AD01 + cheat + description:Infinite lives (top-view levels) + code:22BB-6F0B+6DBB-64DB + cheat + description:Infinite bombs (side-view levels) + code:2264-D760 + cheat + description:Infinite bombs (top-view levels) + code:22B8-0766 + cheat + description:Enable 30 and 99 lives in option menu (99 actually gives 35,081 lives) + code:D987-AFA4 + cheat + description:Keep main weapon when you die (side-view levels) + code:82BA-6FA1 + cheat + description:Keep main weapon when you die (top-view levels) + code:82BC-646B + cheat + description:Multi-jump + code:D961-04D9+CB61-0409+EC61-0469+EE61-04A9+B961-07D9+F361-0709+C961-0D69+4661-0DA9+4B61-0FD9+DD61-0F09+6D61-0F69+ED61-0FA9 + cheat + description:Enable stage select + code:40CC-67DF + cheat + description:Start with 5 bombs on each life (side-view levels) + code:D9BB-AFA1+D9CE-6D0D + cheat + description:Start with 9 bombs on each life (side-view levels) + code:DBBB-AFA1+DBCE-6D0D + cheat + description:Start with 5 bombs on each life (top-view levels) + code:D963-6708+D9CE-6D0F + cheat + description:Start with 9 bombs on each life (top-view levels) + code:DB63-6708+DBCE-6D0F + cheat + description:Always have Scatter Blaster for gun 1 (disable during bonus stages) + code:7E1F84:01 + cheat + description:Always have Missile Launcher for gun 1 (disable during bonus stages) + code:7E1F84:02 + cheat + description:Always have Homing Missile for gun 1 (disable during bonus stages) + code:7E1F84:03 + cheat + description:Always have Torch for gun 1 (disable during bonus stages) + code:7E1F84:04 + cheat + description:Always have Laser for gun 1 (disable during bonus stages) + code:7E1F84:05 + cheat + description:Always have Scatter Blaster for gun 2 (disable during bonus stages) + code:7E1F86:01 + cheat + description:Always have Missile Launcher for gun 2 (disable during bonus stages) + code:7E1F86:02 + cheat + description:Always have Homing Missile for gun 2 (disable during bonus stages) + code:7E1F86:03 + cheat + description:Always have Torch for gun 2 (disable during bonus stages) + code:7E1F86:04 + cheat + description:Always have Laser for gun 2 (disable during bonus stages) + code:7E1F86:05 + cheat + description:Enable stage select (alt) + code:7E1E60:01 + cheat + description:Start on stage 2 + code:7E0086:02 + cheat + description:Start on stage 3 + code:7E0086:03 + cheat + description:Start on stage 4 + code:7E0086:04 + cheat + description:Start on stage 5 + code:7E0086:05 + cheat + description:Start on stage 6 + code:7E0086:06 + +cartridge sha256:c7d622391f7699fb0dc6367e141c894e700cc9bd8abca69f36785e7bc2f42a49 + title:Cool Spot (USA) + cheat + description:Infinite lives + code:402C-D7D1 + cheat + description:Less invincibility time + code:FE89-DF69 + cheat + description:More invincibility time + code:EE89-DF69 + cheat + description:5 seconds picked up + code:D98C-0D05 + cheat + description:1 minute picked up + code:7A8C-0D05 + cheat + description:16% picked up from '7up' + code:FD89-07D5 + cheat + description:Be able to free fellow spot right away + code:DD26-D4D9 + cheat + description:Start with 1 life + code:DF28-D404 + cheat + description:Start with 6 lives + code:D128-D404 + cheat + description:Start with 9 lives + code:DB28-D404 + +cartridge sha256:9674cc269d89a52d1719a487b44acf004fb777cbd58d76b19a2cd25749728215 + title:Cool World (USA) + cheat + description:Infinite lives + code:C2B6-D4DC + cheat + description:Infinite continues + code:C2B2-DF67 + cheat + description:A Nickel for a life costs nothing (must have 1 Nickel) + code:DD8D-046F+DD8D-04AF + cheat + description:Bank deposits cost nothing (must have 5 Nickels) + code:DD8C-0F6F+DD8C-0FAF + cheat + description:Opening a bank account costs nothing (must have 10 Nickels) + code:DDA6-DFA4+DDA6-D4D4 + cheat + description:High-Low game at the Gold Rush costs nothing (must have 5 Nickels) + code:DDC8-ADA5+DDC8-AFD5 + cheat + description:Most Nickels worth 2 on pick-up (must have 5 Nickels) + code:D4BE-07A1+D4B4-6761 + cheat + description:Most Nickels worth 10 on pick-up (must have 5 Nickels) + code:DCBE-07A1+DCB4-6761 + cheat + description:Continue with 9 lives + code:DB8F-6DAD + cheat + description:Start with 1 life + code:DFBE-DD07 + cheat + description:Start with 9 lives + code:DBBE-DD07 + cheat + description:Start with 10 Nickels + code:3187-64DD+3387-640D + cheat + description:Start with 1 Nickel + code:3187-64DD + cheat + description:Invincibility (blinking) + code:7E02BF:FF + cheat + description:Infinite Nickels + code:7E00ED:63 + +cartridge sha256:73533c37fcd3eddce4804eb4c016214d1741c348c349f00d8e6838d341a50df9 + title:Cosmo Gang - The Video (Japan) + cheat + description:Infinite lives + code:7E0200:05 + +cartridge sha256:2602f6e598c711aedb2e3a22414b7869a8490993aef32f53127c408e549afc6d + title:Cosmo Police Galivan II - Arrow of Justice (Japan) + cheat + description:Invincibility + code:CBB4-6DAF+DFB4-6FDF+62B4-6F0F+55B4-6F6F+F4B4-6FAF + cheat + description:Infinite health + code:C23F-6D67 + cheat + description:Infinite lives + code:A2B1-6FA7 + cheat + description:One hit kills + code:B33A-67A4 + cheat + description:Hit anywhere + code:403D-64D4+6D33-0464+6D3D-6FA4 + cheat + description:Invincibility (alt) + code:7E1277:DF + cheat + description:Infinite health (alt) + code:7E126C:60 + cheat + description:Infinite health (alt 2) + code:7E126C:61 + cheat + description:Infinite lives (alt) + code:7E1485:03 + +cartridge sha256:7c722f9941957630467c1784d0eb3f92fbfc0a2a1da3c8f5c27f593eca2a5a04 + title:Cutthroat Island (USA) + cheat + description:Stage select menu after character select screen + code:3C6B-479E + cheat + description:Infinite health - P1 + code:7E09F4:28 + cheat + description:Infinite health - P2 + code:7E0A53:28 + cheat + description:Stage select menu after character select screen (alt) + code:878C9D:EA + cheat + description:9 lives - P1 + code:7E1EF7:09 + cheat + description:9 lives - P2 + code:7E1EF9:09 + +cartridge sha256:c4ae2797fac2586b8640064be6398f2b4f2b3158a07f26c66912b29f7fd197de + title:Cyber Spin (USA) + cheat + description:Infinite power + code:C2B9-ADA1+C2B5-AF01+C2BB-AFA1 + +cartridge sha256:ad31b94ce928ecff605e2b89082154671691509e95d38370ed381437f2c36698 + title:Cybernator (USA) + cheat + description:Protection against some hazards + code:82C9-470C+82C7-4FDC + cheat + description:Infinite credits + code:C234-4FDD + cheat + description:Only 2 P's needed for level 2 Vulcan + code:D461-4D62 + cheat + description:Only 4 P's needed for level 3 Vulcan + code:D061-4FD2 + cheat + description:Only 3 P's needed for level 3 Laser + code:D761-4462 + cheat + description:Only 3 P's needed for level 3 Missile + code:D765-4DD2 + cheat + description:Only 2 P's needed for level 2 Napalm + code:D465-4FD2 + cheat + description:Only 4 P's needed for level 3 Napalm + code:D065-4F62 + cheat + description:Only 2 P's needed for level 2 Punch + code:D465-4462 + cheat + description:Only 3 P's needed for level 3 Punch + code:D765-47D2 + cheat + description:Energy chip worth nothing + code:DD3F-1406 + cheat + description:Energy chip worth more + code:CD3F-1406 + cheat + description:Weapons start at level 2 + code:D4BF-1FDF + cheat + description:Weapons start at level 3 + code:D7BF-1FDF + cheat + description:Start with Lasers + code:62BF-17AF + cheat + description:Start with Homing Missiles + code:62BF-17DF + cheat + description:Start with Napalm + code:62B4-1D6F + cheat + description:Start with 2 credits + code:DFB1-17AF + cheat + description:Start with 6 credits + code:D9B1-17AF + cheat + description:Start with 10 credits + code:DBB1-17AF + cheat + description:Start on level 3.1 + code:D4BD-176F + cheat + description:Start on level 3.2 + code:D7BD-176F + cheat + description:Start on level 3.3 + code:D0BD-176F + cheat + description:Start on level 4.1 + code:D9BD-176F + cheat + description:Start on level 4.2 + code:D1BD-176F + cheat + description:Start on level 5.1 + code:D5BD-176F + cheat + description:Start on level 5.2 + code:D6BD-176F + cheat + description:Start on level 6.1 + code:DBBD-176F + cheat + description:Start on level 7.3 + code:FDBD-176F + cheat + description:Start on level 7.4 + code:FFBD-176F + cheat + description:View the failed ending + code:F4BD-176F + cheat + description:View the successful ending + code:F7BD-176F + +cartridge sha256:71e77fdbd9c865ae07e907549b02549ebe87fa8d436401c485e588c61797754a + title:Cyborg 009 (Japan) + cheat + description:Infinite health + code:7E0AE1:3C + cheat + description:Infinite lives + code:7E1A31:02 + cheat + description:Infinite Super Power + code:7E0AE3:3C + +cartridge sha256:4068add412571bd85adac32dff9835e4a4886077d752adb104fee3908e42b7ef + title:Daffy Duck - The Marvin Missions (USA) + cheat + description:Infinite health + code:C283-3D6F + cheat + description:Infinite ammo (must have some ammo for the gun to be selectable) + code:DD85-17DD + cheat + description:Infinite lives + code:DDB3-3404 + cheat + description:Infinite continues + code:DDA2-C76C + cheat + description:Infinite Nutty attacks + code:C287-34AD + cheat + description:Juice cans set health to 1/2 + code:D121-CD64 + cheat + description:Juice cans set health to 3/4 + code:DB21-CD64 + cheat + description:Gem power-ups worth 0 + code:DD3C-446D + cheat + description:Gem power-ups worth 5 (1 continue) + code:D93C-446D + cheat + description:Gems are free + code:DDA8-44D6 + cheat + description:Freeze Gun ammo is free + code:DDAC-4406 + cheat + description:Freeze Gun ammo is $200 + code:4DAC-4406 + cheat + description:Electricity Gun ammo is free + code:DDAC-44A6 + cheat + description:Electricity Gun ammo is $150 + code:F9AC-44A6 + cheat + description:3-way Gun ammo is free + code:DDAC-4706 + cheat + description:3-way Gun ammo is $150 + code:F9AC-4706 + cheat + description:Bomb Gun ammo is free + code:DDAC-47A6 + cheat + description:Bomb Gun ammo is $150 + code:F9AC-47A6 + cheat + description:Antimatter Gun ammo is free + code:DDA8-4D06 + cheat + description:Antimatter Gun ammo is $200 + code:4DA8-4D06 + cheat + description:Freeze Gun ammo power-ups are worth 20 + code:4D28-4FA7 + cheat + description:Electricity Gun ammo power-ups are worth 20 + code:4D26-1DA7 + cheat + description:Three-way Gun ammo power-ups are worth 20 + code:4D20-C7A7 + cheat + description:Bomb Gun ammo power-ups are worth 20 + code:4D2F-34A7 + cheat + description:Antimatter Gun ammo power-ups are worth 20 + code:4D23-3FA7 + cheat + description:Nutty attacks are free + code:DDA8-4F06 + cheat + description:Nutty attacks are $400 + code:0DA8-4F06 + cheat + description:Jetpack fuel is free + code:DDA8-4DA6 + cheat + description:Fuel is consumed at 1/4 normal rate + code:D1C8-14A7 + cheat + description:Fuel is consumed at 1/2 normal rate + code:DAC8-14A7 + cheat + description:Fuel is consumed at 3/4 normal rate + code:F4C8-14A7 + cheat + description:Fuel power-ups are worth 1/2 as much + code:D12B-17D4 + cheat + description:Fuel power-ups are worth 2x + code:FC2B-17D4 + cheat + description:Buy a life and get a ton of money + code:6DA8-3766 + cheat + description:Bought Freeze Gun ammo is worth 20 + code:4DAE-44D6 + cheat + description:Bought gems worth 0 + code:DDA6-34A6 + cheat + description:Bought gems worth 5 (1 continue) + code:D9A6-34A6 + cheat + description:Bought Electricity Gun ammo is worth 20 + code:4DA9-1406 + cheat + description:Bought Three-way Gun ammo is worth 20 + code:4DA8-1466 + cheat + description:Bought Bomb Gun ammo is worth 20 + code:4DAF-C4A6 + cheat + description:Bought Anti matter Gun ammo is worth 20 + code:4DA5-C7D6 + cheat + description:Bought fuel is worth 1/2 as much + code:D1A2-C7A6 + cheat + description:Bought fuel is worth 2x as much + code:FCA2-C7A6 + cheat + description:Extra lives cost $500 + code:DDA8-4466 + cheat + description:Extra lives cost $1,500 + code:DFA8-4466 + cheat + description:Extra life power-ups don't work + code:DD23-34D4 + cheat + description:Extra life power-ups worth 2 + code:D423-34D4 + cheat + description:Extra life power-ups worth 5 + code:D923-34D4 + cheat + description:Extra lives can't be bought + code:DDA3-3FA6 + cheat + description:2 extra lives for each one purchased + code:D4A3-3FA6 + cheat + description:5 extra lives for each one purchased + code:D9A3-3FA6 + cheat + description:Start with 1 life + code:DFBD-1DA4 + cheat + description:Start with 9 lives (don't set lives in options menu) + code:DBBD-1DA4 + cheat + description:Start with 25 lives (don't set lives in options menu) + code:49BD-1DA4 + cheat + description:Start with 51 lives (don't set lives in options menu) + code:9FBD-1DA4 + cheat + description:Start with 1/2 health + code:D1B4-3DD7 + cheat + description:Start with 3/4 health + code:DBB4-3DD7 + cheat + description:Start with no nutty attacks + code:DDBD-CF04 + cheat + description:Start with 3 nutty attacks + code:D7BD-CF04 + cheat + description:Start with 5 nutty attacks + code:D9BD-CF04 + cheat + description:Start with 7 nutty attacks + code:D5BD-CF04 + cheat + description:Start with 0 gems + code:DDB4-C764 + cheat + description:Start with 10 gems (2 continues) + code:FDB4-C764 + cheat + description:Start with 25 gems (5 continues) + code:49B4-C764 + cheat + description:Start with 10 ammo for all Guns (except blaster) + code:FDBF-CF64 + cheat + description:Start with 50 ammo for all Guns + code:9DBF-CF64 + cheat + description:Start with 90 ammo for all Guns + code:BDBF-CF64 + cheat + description:Start with almost no fuel + code:DDB4-C404 + cheat + description:Start with 2x fuel + code:F8B4-C404 + cheat + description:Start with 3x fuel + code:45B4-C404 + cheat + description:Start with $2,500 + code:D4BD-C7D4 + cheat + description:Start with $3,500 + code:D7BD-C7D4 + cheat + description:Start with $9,500 + code:DBBD-C7D4 + cheat + description:Start with $30,500 + code:7DBD-C7D4 + cheat + description:Start on level 1-2 + code:DFB9-1D04 + cheat + description:Start on level 1-3 + code:D4B9-1D04 + cheat + description:Start on level 1-4 + code:D7B9-1D04 + cheat + description:Start on level 2-1 + code:D0B9-1D04 + cheat + description:Start on level 2-2 + code:D9B9-1D04 + cheat + description:Start on level 2-3 + code:D1B9-1D04 + cheat + description:Start on level 2-4 + code:D5B9-1D04 + cheat + description:Start on level 3-1 + code:D6B9-1D04 + cheat + description:Start on level 3-2 + code:DBB9-1D04 + cheat + description:Start on level 3-3 + code:DCB9-1D04 + cheat + description:Start on level 3-4 + code:D8B9-1D04 + cheat + description:Start on level 4-1 + code:DAB9-1D04 + cheat + description:Start on level 4-2 + code:D2B9-1D04 + cheat + description:Start on level 4-3 + code:D3B9-1D04 + cheat + description:Start on level 4-4 + code:DEB9-1D04 + cheat + description:Start on level 5-1 + code:FDB9-1D04 + cheat + description:Start on level 5-2 + code:FFB9-1D04 + cheat + description:Start on level 5-3 + code:F4B9-1D04 + cheat + description:Start on level 5-4 + code:F7B9-1D04 + cheat + description:Invincibility (blinking) + code:7E1F12:05 + cheat + description:Infinite health (alt) + code:7E1F0E:0C + cheat + description:Infinite lives (alt) + code:7E1F10:99 + cheat + description:Infinite continues (alt) + code:7E1F82:99 + cheat + description:Infinite Nutty attacks (alt) + code:7E1F16:07 + cheat + description:Infinite Fuel + code:7E1F45:10 + cheat + description:Infinite money + code:7E00F7:99+7E00F8:99 + cheat + description:Infinite ammo for Freeze Gun + code:7E1F2A:99 + cheat + description:Infinite ammo for Electricity Gun + code:7E1F2C:99 + cheat + description:Infinite ammo for 3-way Gun + code:7E1F2E:99 + cheat + description:Infinite ammo for Bomb Gun + code:7E1F30:99 + cheat + description:Infinite ammo for Antimatter Gun + code:7E1F32:99 + +cartridge sha256:f3527855afea87b29406700b9dab45ebbb48edcb5a01d59cc2b0986abd3b1dd7 + title:Darius Force (Japan) + cheat + description:Invincibility (can make the screen flash if you use both weapons) + code:7E1000:81 + cheat + description:Infinite lives + code:7E0111:03 + +cartridge sha256:ceb470157576eac3b8b8c16e8ab6b59672409681ffb4232e4ec39dd0cb37ef91 + title:Darius Twin (USA) + cheat + description:Invincibility - P1 + code:C22D-67D9 + cheat + description:Invincibility - P2 + code:C23C-AF60 + cheat + description:Infinite lives - P1 + code:DD35-6FA5 + cheat + description:Infinite lives - P2 + code:DD3B-6FA5 + cheat + description:Hit anywhere - both players + code:6D23-6FA4+C22D-A764+DD28-67A4+DD2E-6D04 + cheat + description:Start with the strongest main weapon and 8 lives - both players + code:3CC3-6DA7+62C3-6467+62C3-6707+CBC3-6D07+D6C3-6D67 + cheat + description:Start with 1 Green Power Cube - P1 + code:62CD-AF67+4ACE-64D7 + cheat + description:Start with 1 Green Power Cube - P2 + code:62CD-A407+4ACE-64D7 + cheat + description:Start with 10 lives - both players + code:FDC3-6D67+CBC3-6D07+3CC3-6DA7 + cheat + description:Start with 15 lives - both players + code:F9C3-6D67+CBC3-6D07+3CC3-6DA7 + cheat + description:Start with 20 lives - both players + code:4DC3-6D67+CBC3-6D07+3CC3-6DA7 + cheat + description:Start with 25 lives - both players + code:49C3-6D67+CBC3-6D07+3CC3-6DA7 + cheat + description:Start on planet B + code:DFB0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet C + code:D4B0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet D + code:D7B0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet E + code:D0B0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet F + code:D9B0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet G + code:D1B0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet H + code:D5B0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet I + code:D6B0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet J + code:DBB0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet K + code:DCB0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Start on planet L + code:D8B0-A7DD+CDB0-A4AD+DDB0-A70D+6AB0-A76D + cheat + description:Invincibility - P1 (alt) + code:01D60C:AD + cheat + description:Invincibility - P2 (alt) + code:01E3A6:AD + cheat + description:Start with 99 lives - both players + code:7E1067:99 + cheat + description:Infinite Shield - P1 + code:7E177B:FF + cheat + description:Infinite Shield - P2 + code:7E188B:FF + cheat + description:Max 1st Gun - P1 + code:7E17A4:08 + cheat + description:Max 1st Gun - P2 + code:7E1835:08 + cheat + description:Max 2nd Gun - P1 + code:7E17EB:08 + cheat + description:Max 2nd Gun - P2 + code:7E177C:08 + cheat + description:Start with 1 Green Power Cube - P1 (alt) + code:00AEF8:2C+00AF06:8D + cheat + description:Start with 1 Green Power Cube - P2 (alt) + code:00AEF8:2C+00AF09:8D + +cartridge sha256:6c1749b24124f74d3aceefa24297b836b6ee7598fc2094f4d065b3c762c898a4 + title:Dark Law - Meaning of Death (Japan) + cheat + description:Sell an item to get maximum cash + code:6D53-7468+D653-74A8 + cheat + description:Fewer random battles + code:6D7E-7DA3 + cheat + description:Any code will open locked doors + code:DD4C-7909 + cheat + description:One hit kills + code:6DC1-8D10 + cheat + description:Infinite walking range in battle + code:DD98-5F19 + +cartridge sha256:e6efb6361af04963f22c772f879a466543f56b3b6a084204fef2dcb4659d82d9 + title:David Crane's Amazing Tennis (USA) + cheat + description:Faster side-to-side movement + code:EA8B-AFDD+D085-A7DD + cheat + description:Even faster side-to-side movement + code:EC8B-AFDD+D185-A7DD + +cartridge sha256:6ce516e3d1a7068cc9732cd3517cfd1e92179f2340c63a244625a1ff49815085 + title:Daze Before Christmas (Europe) + cheat + description:Infinite health + code:7E06F9:05 + cheat + description:Infinite lives + code:7E1E68:04 + +cartridge sha256:300c1937e4b68108302e9b0f49974d1ec6b6c45dd8da69dddc19443f9562ecf4 + title:Death and Return of Superman, The (USA) + cheat + description:Invincibility + code:2D6B-CF6D+ED6C-CFAD + cheat + description:Infinite health + code:C92D-C7DD+992D-C70D+622D-C76D+242D-C7AD+D32F-CDDD + cheat + description:Infinite lives + code:3324-3F6D + cheat + description:Infinite special attacks + code:3323-C76D+D323-C7AD + +cartridge sha256:a33af57e62a46282e3755824cc5fc39870a8eab8a28aaeb1c3817ba2c8e8655e + title:Death Brade (Japan) + cheat + description:Infinite heath - P1 + code:7E0A10:50 + +cartridge sha256:752d24fab240f4dd1dfbfea5ec83438998316806ad44488bf8c84430ca5a2cd0 + title:Demolition Man (USA) + cheat + description:Infinite health + code:F989-376F + cheat + description:Infinite lives + code:C2AC-1FDD + cheat + description:Infinite Grenades + code:82A2-4DA1 + cheat + description:Infinite ammo - Shotgun and Magnum + code:82AA-17AF + cheat + description:Infinite ammo - Shotgun + code:DFAA-14DF + cheat + description:Infinite ammo - Magnum + code:D4BF-1FF0 + cheat + description:Jump 2x higher + code:4D80-67DF + cheat + description:Jump 4x higher + code:FD80-67DF + cheat + description:Jump 8x higher + code:D680-67DF + +cartridge sha256:18d40a807d5f88c5b6a1ad849eec7e0f189225d9a1586037c850f6680b5844de + title:Demon's Crest (USA) + cheat + description:Invincibility after one hit + code:C92A-44A7 + cheat + description:Large health refills full health + code:C9AC-176C + cheat + description:Rapid fire + code:C939-37D7 + cheat + description:Enemies always drop the 20 coin + code:C9A5-370B + cheat + description:First enemy takes longer to kill + code:DB67-C703 + cheat + description:First enemy take less time to kill + code:D467-C703 + cheat + description:More flash time + code:EE3A-1DAF + cheat + description:Die after one hit + code:6927-CDA7 + cheat + description:Super-jump + code:D635-1F0D + cheat + description:Ginseng costs nothing + code:DD38-CFD9 + cheat + description:20 coin worth 999 + code:C9A2-17DC + cheat + description:1 coin worth 999 + code:C9A2-170C + cheat + description:Start a new game with all items + code:A363-44F4+A363-4424+A363-47B4 + cheat + description:Disable anti-cheat (enable to use codes) + code:7E0EEE:00+7E0EED:00 + cheat + description:Invincibility + code:7E103C:30 + cheat + description:Infinite health + code:7E1062:14 + cheat + description:Infinite GP + code:7E1063:E7+7E1064:03 + cheat + description:Infinite Hold spells + code:7E1E30:02 + cheat + description:Infinite Death spells + code:7E1E31:04 + cheat + description:Infinite Shock spells + code:7E1E32:06 + cheat + description:Infinite Imp spells + code:7E1E33:08 + cheat + description:Infinite Shadow spells + code:7E1E34:0A + cheat + description:Infinite Herb potions + code:7E1E35:0C + cheat + description:Infinite Ginseng potions + code:7E1E36:0E + cheat + description:Infinite Mercury potions + code:7E1E37:10 + cheat + description:Infinite Sulfer potions + code:7E1E38:12 + cheat + description:Infinite Elixer potions + code:7E1E39:14 + cheat + description:Have all Powers, Crests, Talismen, Jewels, can hold 5 Spells/Potions + code:7E1E51:FF+7E1E52:FF+7E1E53:FF + +cartridge sha256:a362033d0d7e754d79202b255679186ad799b9e784719614b913ec8c9857ae33 + title:Dennis the Menace (USA) + cheat + description:Infinite courage + code:C9B7-4FD7+C9B7-44A7 + cheat + description:Infinite time + code:C92F-3D9E + cheat + description:Infinite lives + code:C9CB-44AF + +cartridge sha256:606abf536440173ae36466db360c7db6b474beb7a105c8a62bc74a54cbe1c38b + title:Desert Strike - Return to the Gulf (USA) + cheat + description:Infinite ammo + code:223B-07D9 + cheat + description:Infinite fuel + code:DD63-A409 + cheat + description:Infinite lives + code:4A68-04A1 + cheat + description:2x fuel consumption + code:D063-A409 + cheat + description:Faster gun auto-repeat speed + code:DF3C-676F + cheat + description:Slower gun auto-repeat speed + code:F63C-676F + cheat + description:Missiles fly faster + code:D032-6D6F + cheat + description:Hydras fly faster + code:D03E-6DDF + cheat + description:Guns do as much damage as missiles + code:1038-6D6F + cheat + description:Hydras do as much damage as missiles + code:1032-6DDF + cheat + description:Missiles do 250 points of damage + code:EC33-676F + cheat + description:AK47's do 1 point of damage + code:DF39-DF64 + cheat + description:AK47's do 1/2x damage + code:D439-DF64 + cheat + description:AK47's do 2x damage + code:DC39-DF64 + cheat + description:APHIDs do 1 point of damage + code:DF3E-A7DF + cheat + description:APHIDs do 1/2x damage + code:493E-A7DF + cheat + description:APHIDs do 2x damage + code:B13E-A7DF + cheat + description:AAA's do 1 point of damage + code:DF3D-A7DF + cheat + description:AAA's do 1/2x damage + code:DC3D-A7DF + cheat + description:AAA's do 2x damage + code:463D-A7DF + cheat + description:Rapiers do 1 point of damage + code:DF3C-AD6F + cheat + description:Rapiers do 1/2x damage + code:743C-AD6F + cheat + description:Rapiers do 2x damage + code:A63C-AD6F + cheat + description:VDA's do 1 point of damage + code:DF34-A46F + cheat + description:VDA's do 1/2x damage + code:DA34-A46F + cheat + description:VDA's do 2x damage + code:7434-A46F + cheat + description:ZSU's do 1 point of damage + code:DF31-AF6F + cheat + description:ZSU's do 1/2x damage + code:F031-AF6F + cheat + description:ZSU's do 2x damage + code:9D31-AF6F + cheat + description:Speedboats do 1 point of damage + code:DF3F-D464 + cheat + description:Speedboats do 1/2x damage + code:FB3F-D464 + cheat + description:Speedboats do 2x damage + code:103F-D464 + cheat + description:Choppers do 1 point of damage + code:DF37-D4D4 + cheat + description:Choppers do 1/2x damage + code:7437-D4D4 + cheat + description:Choppers do 2x damage + code:A637-D4D4 + cheat + description:M48's do 1 point of damage + code:DF32-A76F + cheat + description:M48's do 1/2x damage + code:7432-A76F + cheat + description:M48's do 2x damage + code:A632-A76F + cheat + description:Crotales do 1 point of damage + code:DF3A-ADDF + cheat + description:Crotales do 1/2x damage + code:743A-ADDF + cheat + description:Crotales do 2x damage + code:A63A-ADDF + cheat + description:AK47's have 1 armor point + code:DF29-0FDD + cheat + description:AK47's have 1/2x armor points + code:D929-0FDD + cheat + description:AK47's have 2x armor points + code:F029-0FDD + cheat + description:APHIDs have 1 armor points + code:DFA7-D76D + cheat + description:APHIDs have 1/2x armor points + code:DAA7-D76D + cheat + description:APHIDs have 2x armor points + code:74A7-D76D + cheat + description:AAA's have 1 armor points + code:DF83-ADD7 + cheat + description:AAA's have 1/2x armor points + code:FB83-ADD7 + cheat + description:AAA's have 2x armor points + code:1083-ADD7 + cheat + description:Rapiers have 1 armor points + code:DFAE-6F6D + cheat + description:Rapiers have 1/2x armor points + code:49AE-6F6D + cheat + description:Rapiers have 2x armor points + code:B1AE-6F6D + cheat + description:VDA's have 1 armor points + code:DFA9-AFDD + cheat + description:VDA's have 1/2x armor points + code:74A9-AFDD + cheat + description:VDA's have 2x armor points + code:A6A9-AFDD + cheat + description:ZSU's have 1 armor points + code:DFAD-DFDF + cheat + description:ZSU's have 1/2x armor points + code:08AD-DFDF + cheat + description:ZSU's have 2x armor points + code:EEAD-DFDF + cheat + description:Speedboats have 1 armor points + code:DFAB-DDDD + cheat + description:Speedboats have 1/2x armor points + code:08AB-DDDD + cheat + description:Speedboats have 2x armor points + code:EEAB-DDDD + cheat + description:Choppers have 1 armor points + code:DFA7-0DDD + cheat + description:Choppers have 1/2x armor points + code:08A7-0DDD + cheat + description:Choppers have 2x armor points + code:EEA7-0DDD + cheat + description:M48's have 1 armor points + code:DFA0-646D + cheat + description:M48's have 1/2x armor points + code:10A0-646D + cheat + description:M48's have 2x armor points + code:DFA0-64AD + cheat + description:Crotales have 1 armor points + code:DFA3-07DD + cheat + description:Crotales have 1/2x armor points + code:52A3-07DD + cheat + description:Crotales have 2x armor points + code:DFA3-070D + cheat + description:AK47 bullets fly slower + code:DD39-D4D4 + cheat + description:APHID bullets fly slower + code:DD3E-A76F + cheat + description:AAA bullets fly slower + code:DD3D-A76F + cheat + description:Rapier bullets fly slower + code:DD3C-AFDF + cheat + description:VDA bullets fly slower + code:DD34-A7DF + cheat + description:ZSU bullets fly slower + code:DD31-A4DF + cheat + description:Speedboat bullets fly slower + code:DD3F-D7D4 + cheat + description:Chopper bullets fly slower + code:DD37-D464 + cheat + description:M48 bullets fly slower + code:DD33-ADDF + cheat + description:Armor starts at 344 + code:DFBC-64A9+DF64-64D1 + cheat + description:Armor starts at 856 + code:D7BC-64A9+D764-64D1 + cheat + description:Armor starts at 1,112 + code:D0BC-64A9+D064-64D1 + cheat + description:Armor starts at 2,136 + code:D6BC-64A9+D664-64D1 + cheat + description:Armor starts at 5,208 + code:F0BC-64A9+F064-64D1 + cheat + description:Fuel starts at 25 + code:FBB1-07DC + cheat + description:Fuel starts at 50 + code:74B1-07DC + cheat + description:Fuel starts at 75 + code:08B1-07DC + cheat + description:Fuel starts at 150 + code:B1B1-07DC + cheat + description:Fuel starts at 200 + code:A6B1-07DC + cheat + description:Fuel starts at 868 + code:D7B1-070C + cheat + description:Guns start at 154 rounds remaining + code:DD38-6D0F + cheat + description:Guns start at 666 rounds remaining + code:D438-6D0F + cheat + description:Guns start at 2,458 rounds remaining + code:DB38-6D0F + cheat + description:Guns start at 5,018 rounds remaining + code:F738-6D0F + cheat + description:Guns start at 9,882 rounds remaining + code:4138-6D0F + cheat + description:Start with 10 hydras + code:DC3A-676F + cheat + description:Start with 50 hydras + code:743A-676F + cheat + description:Start with 100 hydras + code:103A-676F + cheat + description:Start with 250 hydras + code:EC3A-676F + cheat + description:Start with 1 missile + code:DF33-67DF + cheat + description:Start with 20 missiles + code:F033-67DF + cheat + description:Start with 50 missiles + code:7433-67DF + cheat + description:Start with 100 missiles + code:1033-67DF + cheat + description:Start with 250 missiles + code:EC33-67DF + cheat + description:Start with 1 life + code:DFB1-0F6C + cheat + description:Start with 5 lives + code:D9B1-0F6C + cheat + description:Start with 7 lives + code:D5B1-0F6C + cheat + description:Start with 10 lives + code:DCB1-0F6C + cheat + description:Start with 20 lives + code:F0B1-0F6C + cheat + description:Start with 50 lives + code:74B1-0F6C + cheat + description:Start with 99 lives + code:17B1-0F6C + +cartridge sha256:337e643d3e63915de06429992f306e8d2b73aed6849b795f9c855c2d03c18180 + title:D-Force (USA) + cheat + description:Infinite lives + code:3CCA-D4DD + cheat + description:Continue equipped with unguided missiles + code:7D6C-D40F+2C6C-D46F+FD6C-D7DF + cheat + description:Loss of a life does not decrease cannon power at normal difficulty (except on continues) + code:DDC7-DD0F + cheat + description:Loss of a life does not decrease cannon power at hard difficulty (except on continues) + code:DDC0-D4DF + cheat + description:Pink power-up increases missile power along with cannon power + code:DA3D-6464 + cheat + description:Continue with 10 lives + code:7168-D70F+C668-D76F + cheat + description:Continue with 12 lives + code:C868-D70F+C068-D76F + cheat + description:Continue with 14 lives + code:CF68-D70F+EF68-D76F + cheat + description:Continue with 16 lives + code:9E68-D70F+C068-D76F + cheat + description:Continue with cannon power at level 2 + code:DF68-DF0F+DE68-DD6F + cheat + description:Continue with cannon power at level 3 + code:D468-DF0F+DE68-DD6F + cheat + description:Continue with cannon power at level 4 + code:D768-DF0F+DE68-DD6F + cheat + description:Continue with cannon power at level 6 + code:D968-DF0F+DE68-DD6F + cheat + description:Continue with cannon power at level 8 + code:D568-DF0F+DE68-DD6F + cheat + description:Continue with cannon power at level 10 + code:DB68-DF0F+DE68-DD6F + cheat + description:Continue with cannon power at level 12 + code:D868-DF0F+DE68-DD6F + cheat + description:Start with cannon power at level 2 + code:DFB6-DF6D + cheat + description:Start with cannon power at level 3 + code:D4B6-DF6D + cheat + description:Start with cannon power at level 4 + code:D7B6-DF6D + cheat + description:Start with cannon power at level 6 + code:D9B6-DF6D + cheat + description:Start with cannon power at level 8 + code:D5B6-DF6D + cheat + description:Start with cannon power at level 10 + code:DBB6-DF6D + cheat + description:Start with cannon power at level 12 + code:D8B6-DF6D + cheat + description:Start equipped with unguided missiles + code:DAB6-D76D+FDB6-D4AD + cheat + description:Start with 10 lives + code:7168-D5F6+C668-D596 + cheat + description:Start with 12 lives + code:C868-D5F6+C068-D596 + cheat + description:Start with 14 lives + code:CF68-D5F6+EF68-D596 + cheat + description:Start with 16 lives + code:9E68-D5F6+C068-D596 + +cartridge sha256:7dbfc44d28a46e6d399628e43086aa9fd0b2abeda4c108751a5ad91c102c3aaf + title:Dino City (USA) + cheat + description:No harm from most enemies + code:6DA6-6D69 + cheat + description:No harm if swallowed by a monster + code:C23B-A7F9+C232-67B1 + cheat + description:Infinite plays - both players + code:C26E-6D2D + cheat + description:Infinite time (disable in bonus stage) + code:8269-DF90 + cheat + description:Infinite credits - both players + code:C260-67F7 + cheat + description:Clock runs faster + code:7A64-D420 + cheat + description:Clock runs slower + code:ED64-D420 + cheat + description:Clock runs much slower + code:ED64-D420+DF64-D7F0 + cheat + description:Rex jumps higher + code:EC6B-DFBE + cheat + description:Rex jumps much higher + code:E66B-DFBE + cheat + description:Tops jumps higher + code:EC8A-D793 + cheat + description:Tops jumps much higher + code:E68A-D793 + cheat + description:Timmy and Jamie jump higher + code:EC22-DF22 + cheat + description:Timmy and Jamie jump much higher + code:E622-DF22 + cheat + description:Collect 2 eggs for extra play instead of 50 + code:D427-6D2D + cheat + description:Collect 5 eggs for extra play + code:D927-6D2D + cheat + description:Collect 10 eggs for extra play + code:FD27-6D2D + cheat + description:Collect 15 eggs for extra play + code:F927-6D2D + cheat + description:Collect 25 eggs for extra play + code:4927-6D2D + cheat + description:Collect 75 eggs for extra play + code:5927-6D2D + cheat + description:Collect 99 eggs for extra play + code:BB27-6D2D + cheat + description:1 play per game instead of 3 - both players + code:DF6D-D7BD + cheat + description:2 plays per game - both players + code:D46D-D7BD + cheat + description:4 plays per game - both players + code:D06D-D7BD + cheat + description:5 plays per game - both players + code:D96D-D7BD + cheat + description:7 plays per game - both players + code:D56D-D7BD + cheat + description:9 plays per game - both players + code:DB6D-D7BD + cheat + description:Start with 1 credit instead of 3 - P1 + code:DFC2-A494 + cheat + description:Start with 2 credits - P1 + code:D4C2-A494 + cheat + description:Start with 5 credits - P1 + code:D9C2-A494 + cheat + description:Start with 7 credits - P1 + code:D5C2-A494 + cheat + description:Start with 9 credits - P1 + code:DBC2-A494 + cheat + description:Start with No credits - P1 + code:DDC2-A494 + cheat + description:Start with 1 credit instead of 3 - P2 + code:DFCF-DFF7 + cheat + description:Start with 2 credits - P2 + code:D4CF-DFF7 + cheat + description:Start with 5 credits - P2 + code:D9CF-DFF7 + cheat + description:Start with 7 credits - P2 + code:D5CF-DFF7 + cheat + description:Start with 9 credits - P2 + code:DBCF-DFF7 + cheat + description:Start with No credits - P2 + code:DDCF-DFF7 + cheat + description:Infinite health - P1 + code:7E16ED:03 + +cartridge sha256:10e07e9e094e77a2b71bab3bac1d79a62b7a7bfdb80111044b1f9c64645c622f + title:Donald in Maui Mallard (Europe) + cheat + description:Infinite health + code:7E0DD3:64 + cheat + description:Infinite lives + code:7E1F4A:03 + cheat + description:Infinite Zapps + code:7E0DDB:0A + cheat + description:Infinite Homers + code:7E0DDD:0A + +cartridge sha256:fa8cacf5bbfc39ee6bbaa557adf89133d60d42f6cf9e1db30d5a36a469f74d15 + title:Donkey Kong Country (USA) + cheat + description:Invincibility (no lockup) + code:1DCC-CA7A+F6CF-13EA+F6CC-3E7A + cheat + description:Invincibility + code:1DCC-CA7A + cheat + description:Almost invincible (disable if you get stuck) + code:1DCC-CA7A+1DCA-C2EA + cheat + description:Infinite lives + code:C2C1-4A9C + cheat + description:Infinite lives (alt) + code:C2C9-4E2C+C2C1-4A9C + cheat + description:10 Bananas needed for extra life + code:DBC1-3D6D+DCC1-34AD+DBC9-340D+DCC1-3D6D + cheat + description:25 Bananas needed for extra life + code:F6C1-3D6D+FBC1-34AD+F6C9-340D+FBC1-3D6D + cheat + description:50 Bananas needed for extra life + code:7FC1-3D6D+74C1-34AD+7FC9-340D+74C1-3D6D + cheat + description:75 Bananas needed for extra life + code:0CC1-3D6D+08C1-34AD+0CC9-340D+08C1-3D6D + cheat + description:Easy level exit (press start and select) + code:DDB9-3DD4 + cheat + description:Easy level exit (press start and select) (alt) + code:DDB9-3DD4+DDB0-34A4 + cheat + description:Bad buddy code (In 2P team mode, the inactive player can press select to gain control) + code:DD8B-C28A + cheat + description:Bad buddy code (In 2P team mode, the inactive player can press select to gain control) (alt) + code:DD8B-C28A+DD88-CE5A + cheat + description:Both Kongs return (get both Kongs back on map screen after dying, doesn't work when you fall off the screen) + code:D76B-337E + cheat + description:Return of Kong (when your last Kong gets hit, the other one returns (reset if you get stuck). Must have had both Kongs at some point). + code:EE65-C37E + cheat + description:Keep Animals between stages + code:1D6B-3FDD+196A-333D + cheat + description:Keep Animals between stages (alt) + code:D76B-3FDD+196A-333D + cheat + description:Keep Animals between stages (alt) + code:1D6B-3FDD+196A-333D+1D6B-3D6D+166A-3ECD + cheat + description:Multi-jump + code:6D84-33EA+4084-1273+6D84-1353+2D87-1273 + cheat + description:Multi-jump - Expresso (the Ostrich) + code:EE80-C373 + cheat + description:High-jump - Donkey Kong + code:A081-1273 + cheat + description:Super-jump - Donkey Kong + code:2D81-1273 + cheat + description:Mega-jump - Donkey Kong + code:3D81-1273 + cheat + description:Moon-jump - Donkey Kong + code:EE81-1273 + cheat + description:High-jump - Diddy Kong + code:8081-1E73 + cheat + description:Super-jump - Diddy Kong + code:AD81-1E73 + cheat + description:Mega-jump - Diddy Kong + code:2D81-1E73 + cheat + description:Moon-jump - Diddy Kong + code:EE81-1E73 + cheat + description:High-jump - Animals + code:A08F-C273 + cheat + description:Super-jump - Animals + code:2D8F-C273 + cheat + description:Mega-jump - Animals + code:3D8F-C273 + cheat + description:Moon-jump - Animals + code:EE8F-C273 + cheat + description:High-jump - Donkey Kong + code:A081-1273+A086-13E3 + cheat + description:Super-jump - Donkey Kong + code:2D81-1273+2D86-13E3 + cheat + description:Mega-Jump - Donkey Kong + code:3D81-1273+3D86-13E3 + cheat + description:High-jump - Diddy Kong + code:8081-1E73+808B-1AE3 + cheat + description:Super-jump - Diddy Kong + code:AD81-1E73+AD8B-1AE3 + cheat + description:Mega-Jump - Diddy Kong + code:2D81-1E73+2D8B-1AE3 + cheat + description:High-jump - all Animals + code:A08F-C273+A087-C3E3 + cheat + description:Super-jump - all Animals + code:2D8F-C273+2D87-C3E3 + cheat + description:Mega-jump - all Animals + code:3D8F-C273+3087-C3E3 + cheat + description:See the ending + code:CD68-3FDD+226A-333D + cheat + description:Start With 8 lives + code:D568-C34D+D568-C33D + cheat + description:Start With 11 lives + code:DC68-C34D+DC68-C33D + cheat + description:Start With 16 lives + code:DE68-C34D+DE68-C33D + cheat + description:Start With 26 lives + code:FB68-C34D+FB68-C33D + cheat + description:Start With 51 lives + code:7468-C34D+7468-C33D + cheat + description:Start With 76 lives + code:0868-C34D+0868-C33D + cheat + description:Start With 100 lives + code:1768-C34D+1768-C33D + cheat + description:Start with 255 lives + code:EE68-C34D + cheat + description:Return of Kong (alt) + code:7E0579:01 + +cartridge sha256:df2644d435330192a13768cc1f79c5aa3084a64217a5250c6dd4ffdbe2175be4 + title:Donkey Kong Country (USA) (Rev 1) + cheat + description:Invincibility (no lockup) + code:1DCA-C2EA+F6C0-1A8A+F6C2-3AEA + cheat + description:Invincibility + code:1DCA-C2EA + cheat + description:Almost invincible (disable if you get stuck) + code:1DCA-C2EA + cheat + description:Infinite lives + code:C2C1-4A2C + cheat + description:Easy level exit (press start and select) + code:DDB0-34A4 + cheat + description:Bad buddy code (In 2P team mode, the inactive player can press select to gain control) + code:DD88-CE5A + cheat + description:Both Kongs return (get both Kongs back on map screen after dying, doesn't work when you fall off the screen) + code:D76C-327E + cheat + description:Return of Kong (when your last Kong gets hit, the other one returns (reset if you get stuck). Must have had both Kongs at some point). + code:EE66-C27E + cheat + description:Keep Animals + code:1D6B-3D6D+166A-3ECD + cheat + description:Multi-jump + code:6D89-3A8A+4080-13E3+6D89-1A73+2D89-13E3 + cheat + description:Multi-jump - Expresso (the Ostrich) + code:EE81-CEE3 + cheat + description:High-jump - Donkey Kong + code:A086-13E3 + cheat + description:Super-jump - Donkey Kong + code:2D86-13E3 + cheat + description:Mega-jump - Donkey Kong + code:3D86-13E3 + cheat + description:Moon-jump - Donkey Kong + code:EE86-13E3 + cheat + description:High-jump - Diddy Kong + code:808B-1AE3 + cheat + description:Super-jump - Diddy Kong + code:AD8B-1AE3 + cheat + description:Mega-jump - Diddy Kong + code:2D8B-1AE3 + cheat + description:Moon-jump - Diddy Kong + code:EE8B-1AE3 + cheat + description:High-jump - Animals + code:A087-C3E3 + cheat + description:Super-jump - Animals + code:2D87-C3E3 + cheat + description:Mega-jump - Animals + code:3087-C3E3 + cheat + description:Moon-jump - Animals + code:EE87-C3E3 + cheat + description:Land animals roll attack + code:C4A2-CA7A + cheat + description:Start with 255 lives + code:EE68-C33D + cheat + description:Return of Kong (alt) + code:7E0579:01 + +cartridge sha256:628147468c3539283197f58f03b94df49758a332831857481ea9cc31645f0527 + title:Donkey Kong Country (USA) (Rev 2) + cheat + description:Invincibility (no lockup) + code:1DC2-C3EA+F6C9-128A+F6C3-32EA + cheat + description:Invincibility + code:1DC2-C3EA + cheat + description:Infinite lives + code:C2C5-4A2C + cheat + description:Easy level exit (press start and select) + code:DDB9-3764 + cheat + description:Bad buddy code (In 2P team mode, the inactive player can press select to gain control) + code:DD82-CEEA + cheat + description:Both Kongs return (get both Kongs back on map screen after dying, doesn't work when you fall off the screen) + code:D76C-337E + cheat + description:Return of Kong (when your last Kong gets hit, the other one returns (reset if you get stuck). Must have had both Kongs at some point). + code:EE66-C37E + cheat + description:Multi-jump + code:6D85-327A+4081-1E53+6D85-1A83+2D85-1E53 + cheat + description:Multi-jump - Expresso (the Ostrich) + code:EE8B-CA53 + cheat + description:High-jump - Donkey Kong + code:A08C-1E53 + cheat + description:Super-jump - Donkey Kong + code:2D8C-1E53 + cheat + description:Mega-jump - Donkey Kong + code:308C-1E53 + cheat + description:Moon-jump - Donkey Kong + code:EE8C-1E53 + cheat + description:High-jump - Diddy Kong + code:8088-1253 + cheat + description:Super-jump - Diddy Kong + code:AD88-1253 + cheat + description:Mega-jump - Diddy Kong + code:2D88-1253 + cheat + description:Moon-jump - Diddy Kong + code:EE88-1253 + cheat + description:High-jump - Animals + code:A089-CE53 + cheat + description:Super-jump - Animals + code:2D89-CE53 + cheat + description:Mega-jump - Animals + code:3089-CE53 + cheat + description:Moon-jump - Animals + code:EE89-CE53 + cheat + description:Land animals can roll attack + code:A98B-327A + cheat + description:Start with 255 lives + code:EE63-333D + cheat + description:Return of Kong (alt) + code:7E0579:01 + +cartridge sha256:b79c2bb86f6fc76e1fc61c62fc16d51c664c381e58bc2933be643bbc4d8b610c + title:Donkey Kong Country 2 - Diddy's Kong Quest (USA) (En,Fr) (Rev 1) + cheat + description:Master code - Must be entered + code:E6EE-A7D7+6DA4-1A8B+6D8F-C33E + cheat + description:Invincibility + code:CB2C-1A4D+FD2C-1A1D+DD2C-1ACD + cheat + description:Infinite lives + code:C2A1-CE5B+C2A5-C37B + cheat + description:Get 2 lives per 100 bananas collected + code:D4A1-437C+D4A5-4AEC + cheat + description:Get 5 lives per 100 bananas collected + code:D9A1-437C+D9A5-4AEC + cheat + description:Get 255 lives per 100 bananas collected + code:EEA1-437C + cheat + description:When your last Kong is hit, the other returns + code:EEC2-1A1D+EECC-CA4D + cheat + description:Easy level exit (press start and select) + code:DD6C-C7D4+DD62-C4A4 + cheat + description:Kong family coins don't get used up + code:C2B9-13B7+C2B1-13F7 + cheat + description:Kremcoins don't get used up + code:C2B9-1297+C2B1-1A27 + cheat + description:Multi-jump + code:DDBD-CA44+D5BD-3214+DBB2-3244+DD8E-121D+6787-C334 + cheat + description:Mega-jump for Diddy + code:EDD0-735A + cheat + description:Super-jump - Diddy + code:E7D0-735A + cheat + description:Jump higher - Diddy + code:E1D0-735A + cheat + description:Jump lower - Diddy + code:EBD0-735A + cheat + description:Jump much lower - Diddy + code:ECD0-735A + cheat + description:Mega-jump - Dixie + code:EDD7-5AEA + cheat + description:Super-jump - Dixie + code:E7D7-5AEA + cheat + description:Jump higher - Dixie + code:E5D7-5AEA + cheat + description:Jump lower - Dixie + code:EBD7-5AEA + cheat + description:Jump much lower - Dixie + code:ECD7-5AEA + cheat + description:Mega-jump - Rambi with Diddy riding + code:EFDD-535A + cheat + description:Super-jump - Rambi with Diddy riding + code:E7DD-535A + cheat + description:Rambi jumps higher with Diddy riding + code:E5DD-535A + cheat + description:Rambi doesn't jump as high with Diddy riding + code:ECDD-535A + cheat + description:Start with more kong family coins + code:626D-4EBD + cheat + description:Start with more Kremcoins + code:626D-432D + cheat + description:Start with 3 lives + code:D465-3D67+D46C-3D07 + cheat + description:Start with 10 lives + code:DB65-3D67+DB6C-3D07 + cheat + description:Start with 25 lives + code:F665-3D67+F66C-3D07 + cheat + description:Start with 50 lives + code:7F65-3D67+7F6C-3D07 + cheat + description:Start with 99 lives + code:1765-3D67+176C-3D07 + cheat + description:Start with 255 lives + code:EE65-3D67 + +cartridge sha256:35421a9af9dd011b40b91f792192af9f99c93201d8d394026bdfb42cbf2d8633 + title:Donkey Kong Country 2 - Diddy's Kong Quest (USA) (En,Fr) + cheat + description:Master code - Must be entered + code:E6EE-A7D7+6DAF-12EB+6D8D-C33E + cheat + description:Invincibility + code:4028-434D + cheat + description:Infinite lives + code:C2A1-CE5B+C2A5-C37B + cheat + description:Get 2 lives per 100 bananas collected + code:D4A1-437C+D4A5-4AEC + cheat + description:Get 5 lives per 100 bananas collected + code:D9A1-437C+D9A5-4AEC + cheat + description:Get 255 lives per 100 bananas collected + code:EEA1-437C + cheat + description:When your last Kong is hit, the other returns + code:EEC2-1A1D+EECC-CA4D + cheat + description:Easy level exit (press start and select) + code:DD6C-C7D4+DD62-C4A4 + cheat + description:Kong family coins don't get used up + code:C2B9-13B7+C2B1-13F7 + cheat + description:Kremcoins don't get used up + code:C2B9-1297+C2B1-1A27 + cheat + description:Multi-jump + code:4DAF-121F+54AF-12CF+A0AF-123F+1DAF-134F + cheat + description:Mega-jump for Diddy + code:EDD0-735A + cheat + description:Super-jump - Diddy + code:E7D0-735A + cheat + description:Jump higher - Diddy + code:E1D0-735A + cheat + description:Jump lower - Diddy + code:EBD0-735A + cheat + description:Jump much lower - Diddy + code:ECD0-735A + cheat + description:Mega-jump - Dixie + code:EDD7-5AEA + cheat + description:Super-jump - Dixie + code:E7D7-5AEA + cheat + description:Jump higher - Dixie + code:E5D7-5AEA + cheat + description:Jump lower - Dixie + code:EBD7-5AEA + cheat + description:Jump much lower - Dixie + code:ECD7-5AEA + cheat + description:Mega-jump - Rambi with Diddy riding + code:EFDD-535A + cheat + description:Super-jump - Rambi with Diddy riding + code:E7DD-535A + cheat + description:Rambi jumps higher with Diddy riding + code:E5DD-535A + cheat + description:Rambi doesn't jump as high with Diddy riding + code:ECDD-535A + cheat + description:Start with more kong family coins + code:626D-4EBD + cheat + description:Start with more Kremcoins + code:626D-432D + cheat + description:Start with 3 lives + code:D465-3D67+D46C-3D07 + cheat + description:Start with 10 lives + code:DB65-3D67+DB6C-3D07 + cheat + description:Start with 25 lives + code:F665-3D67+F66C-3D07 + cheat + description:Start with 50 lives + code:7F65-3D67+7F6C-3D07 + cheat + description:Start with 99 lives + code:1765-3D67+176C-3D07 + cheat + description:Start with 255 lives + code:EE65-3D67 + +cartridge sha256:2277a2d8dddb01fe5cb0ae9a0fa225d42b3a11adccaeafa18e3c339b3794a32b + title:Donkey Kong Country 3 - Dixie Kong's Double Trouble! (USA) (En,Fr) + cheat + description:Invincibility + code:B768-C34D + cheat + description:Invincibility (alt) + code:CBA0-CECF+DBA0-CE3F+DDA9-CA4F + cheat + description:Infinite lives + code:CB6E-73CD + cheat + description:Infinite bear coins + code:DBB8-729D + cheat + description:Get Funky's Gyrocopter with no need for DK coins + code:6D6C-7EFF+6D62-722F + cheat + description:Multi-jump + code:4D2B-3E1F+5F2B-3ECF+BD2B-3E3F+1D2C-3A4F + +cartridge sha256:d45e26eb10c323ecd480e5f2326b223e29264c3adde67f48f0d2791128e519e8 + title:Doom (USA) + cheat + description:Infinite health + code:6EDE-955D+C3DE-958D+9CDE-95ED+5DDD-B07D+6DDD-B05D2 + cheat + description:Start with mega health and mega armor + code:BDEA-B053+62EA-B953 + cheat + description:Start with more ammo + code:E3EA-B153 + cheat + description:Heat vision/color blind mode + code:CBD3-B17F + cheat + description:Select "The Shores of Hell" or "Inferno" in any skill level + code:D7CF-F953 + +cartridge sha256:8d4ada4f98464d176ae7f0fb8a20032056680f3241637a0f903f23f31f41ff36 + title:Doom Troopers (USA) + cheat + description:Invincibility + code:7E0C99:01 + cheat + description:Infinite health + code:7E0C31:64 + cheat + description:Infinite lives + code:7E0CB3:03+7E0102:03 + cheat + description:Infinite ammo + code:7E00E6:63 + cheat + description:Infinite special weapon ammo + code:7E00EA:0A + cheat + description:Die to complete level (don't use with infinite lives code) + code:7E0102:01 + +cartridge sha256:bb915b286b33842e39e9022366169233a4041515c7ecc60ac428420b28e48dd5 + title:Doomsday Warrior (USA) + cheat + description:Infinite health and matches last forever + code:82C7-046F + cheat + description:Always get 4 bonus points for improving abilities + code:CBB2-ADDD+D0B2-AD0D+6DB2-A46D + cheat + description:On normal level, start with all stats at 2 bars instead of 0 + code:D9B9-64DD + cheat + description:First 6 fights are against Sledge + code:DDB0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 6 fights are against Layban + code:DFB0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 6 fights are against Amon + code:D4B0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 6 fights are against Daisy + code:D7B0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 6 fights are against P-Lump + code:D0B0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 6 fights are against Grimrock + code:D9B0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 6 fights are against Nuform + code:D1B0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 7 fights are against Shadow + code:D5B0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 6 fights are against Ashura + code:D6B0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:First 6 fights are against Main + code:DBB0-ADAD+6DB0-AFDD+E9B0-AF0D + cheat + description:All fights are in order (you don't choose your opponent) + code:DDB7-AFAD + cheat + description:You can heal completely, not just to the top of each segment + code:DD83-D4AF + cheat + description:Don't heal at all + code:3C8E-DDAF + cheat + description:Infinite health - P1 + code:7E02C6:64 + cheat + description:Infinite health - P2 + code:7E03C6:64 + cheat + description:No health - P1 + code:7E02C6:00 + cheat + description:No health - P2 + code:7E03C6:00 + +cartridge sha256:b32aa9cbf8f6baacc84f6418fa6fbc33b9ce71458fecc91275aafdbf6f743a99 + title:Double Dragon V - The Shadow Falls (USA) + cheat + description:Always win - P1 + code:DDAB-3DAE + cheat + description:Can't perform special moves - P2/CPU + code:B3C8-CFBF+B3C6-CDBF+BAC9-3FBF + cheat + description:Pick up to 9 points of any attribute instead of 5 + code:DBBC-1F27 + cheat + description:Harder to recover from dizziness + code:3C85-CF07 + cheat + description:Dizziness doesn't last long + code:D685-C407 + cheat + description:Start with 50% health - both characters + code:46C6-340D + cheat + description:Start with 25% health - both characters + code:F0C6-340D + cheat + description:Infinite health - P1 + code:7E1B8D:50 + cheat + description:Infinite health - P2 + code:7E1C8A:50 + cheat + description:No health - P1 + code:7E1B8D:00 + cheat + description:No health - P2 + code:7E1C8A:00 + cheat + description:Bosses unlocked cheat enabled + code:7F0068:01 + cheat + description:Stuns disabled cheat enabled + code:7F006A:01 + cheat + description:Throwing disabled cheat enabled + code:7F006C:01 + cheat + description:P1 is Billy Lee + code:7E0632:00 + cheat + description:P1 is Jimmy Lee + code:7E0632:01 + cheat + description:P1 is Jawbreaker + code:7E0632:02 + cheat + description:P1 is Icepick + code:7E0632:03 + cheat + description:P1 is S Master + code:7E0632:04 + cheat + description:P1 is Bones + code:7E0632:05 + cheat + description:P1 is Sickle + code:7E0632:06 + cheat + description:P1 is Blade + code:7E0632:07 + cheat + description:P1 is T Happy + code:7E0632:08 + cheat + description:P1 is Countdown + code:7E0632:09 + cheat + description:P1 is Dominique + code:7E0632:0A + cheat + description:P1 is Sekka + code:7E0632:0B + cheat + description:P2 is Billy Lee + code:7E0633:00 + cheat + description:P2 is Jimmy Lee + code:7E0633:01 + cheat + description:P2 is Jawbreaker + code:7E0633:02 + cheat + description:P2 is Icepick + code:7E0633:03 + cheat + description:P2 is S Master + code:7E0633:04 + cheat + description:P2 is Bones + code:7E0633:05 + cheat + description:P2 is Sickle + code:7E0633:06 + cheat + description:P2 is Blade + code:7E0633:07 + cheat + description:P2 is T Happy + code:7E0633:08 + cheat + description:P2 is Countdown + code:7E0633:09 + cheat + description:P2 is Dominique + code:7E0633:0A + cheat + description:P2 is Sekka + code:7E0633:0B + +cartridge sha256:d98d7da1e7636e067563e2e480d7dfbc013b7e9bdf1329fd61c5cacac0293e1d + title:Dragon - The Bruce Lee Story (USA) + cheat + description:Infinite health (disable before stage ends) + code:7E00D9:FF + cheat + description:Infinite fighting power + code:7E00DB:FF + cheat + description:0 HP - Enemy 1 + code:7E01D9:00 + cheat + description:0 HP - Enemy 2 + code:7E02D9:00 + cheat + description:Infinite time (turn on only in a timed fight and off after defeating your opponent) + code:7E2082:63 + cheat + description:Hyper Mode - P1 + code:7E003E:01 + cheat + description:Hyper Mode - P2/Enemy 1 + code:7E013E:01 + cheat + description:Hyper Mode - P3/Enemy 2 + code:7E023E:01 + cheat + description:P1 Knocks Out Easier + code:7E0093:02 + cheat + description:P2 Knocks Out Easier + code:7E0193:02 + cheat + description:P3 Knocks Out Easier + code:7E0293:02 + cheat + description:P1 Can't Be Hit + code:7E0095:44 + cheat + description:P2 Can't Be Hit + code:7E0195:44 + cheat + description:P3 Can't Be Hit + code:7E0295:44 + cheat + description:Start in Alley outside kitchen (version 2) + code:7E539E:01 + cheat + description:Start in Alley outside kitchen + code:7E539E:02 + cheat + description:Start in the Seattle Gym + code:7E539E:03 + cheat + description:Start in the George Wu Gym + code:7E539E:04 + cheat + description:Start in Film Set + code:7E539E:05 + cheat + description:Start in Bruce's Kwoon + code:7E539E:06 + cheat + description:Start in Virgin Gym + code:7E539E:07 + cheat + description:Start in the Big Boss Film set (version 2) + code:7E539E:08 + cheat + description:Start in the Big Boss Film set + code:7E539E:09 + cheat + description:Start in the Enter The Dragon set + code:7E539E:0A + cheat + description:Start in the Armored Boss Arena + code:7E539E:0B + cheat + description:Start in the Machine + code:7E539E:0C + +cartridge sha256:32226fb8b126261dfec279aea51b2fe01e0c7bfbf26699ddcceb750a0d3a9fc0 + title:Dragon Ball Z - Hyper Dimension (Japan) + cheat + description:One hit kills + code:CBAB-0D0F+DFAB-0D6F+DDAB-0DAF+62AB-04AF+1DAB-07DF + +cartridge sha256:a3b1cae3fe55fe52c035ab122e7f850640b0935524496d45b1915ca3c8a934f4 + title:Dragon View (USA) + cheat + description:Infinite health (may crash at the end of Ortah Temple if using an emulator) + code:CE65-4586 + cheat + description:Infinite Jade + code:CE34-3106 + cheat + description:Infinite Bombs + code:E23-C9:A2 + cheat + description:Infinite Potions + code:CE26-41A3 + cheat + description:Infinite magic for rings + code:C237-4116 + cheat + description:Max level after killing a Demon + code:7834-1F67 + cheat + description:Sell a fruit to get 254 fruit + code:6D37-196B+7534-C0AB + cheat + description:Infinite HP + code:7E6FCA:B8 + cheat + description:Max HP + code:7E6FCB:BE+7E6FCB:BE + cheat + description:Max EXP + code:7E7095:E7+7E7096:03 + cheat + description:Max money (Jade) + code:7E2131:0F+7E2132:27 + cheat + description:Max attack power + code:7E98E9:FF + cheat + description:Max defense power + code:7E98EA:FF + +cartridge sha256:49a1f9f5e6084b3daa1b13ab5a37ebe8bd3cf20e1c7429fbf722298092893e81 + title:Dragon's Lair (USA) + cheat + description:Infinite health + code:3C8C-0FA4 + cheat + description:Infinite time + code:4A84-64D4 + cheat + description:Infinite lives + code:3C62-D70F + cheat + description:Start with 1 life + code:DD89-0404 + cheat + description:Start with 6 lives + code:D989-0404 + cheat + description:Start with 9 lives + code:D689-0404 + cheat + description:Start with the Dagger + code:DF86-0DD4 + cheat + description:Start with the Shuriken + code:D486-0DD4 + cheat + description:Slow timer + code:5D89-6D04 + cheat + description:Faster timer + code:4989-6D04 + cheat + description:1 coin gives 10 + code:DF88-0F64 + cheat + description:Infinite health (alt) + code:7E1036:04 + cheat + description:Infinite time (alt) + code:7E1033:09 + cheat + description:Infinite lives (alt) + code:7E1028:03 + cheat + description:Infinite Gold + code:7E1030:09 + +cartridge sha256:74910ce01d19d25cb97a243a51f21c3d522f02fb116682f60440da3292bb14f7 + title:Drakkhen (USA) + cheat + description:Protection from some attacks + code:8E3D-696D+8E30-A408+8EA2-0113 + cheat + description:Magic points restored 50 points at a time while player is on screen + code:7433-6FD8 + cheat + description:Magic points restored 10 points at a time while player is on screen + code:DC33-6FD8 + cheat + description:Magic points don't decrease except in battle + code:8E27-6D28 + +cartridge sha256:1a79d51a2ad7dd4848205a07ff8e5d873b155dc420de5e52158c9bab935e05c3 + title:Dream TV (USA) + cheat + description:Almost infinite health + code:8FA6-3DA8+8FAA-3FA8 + cheat + description:Infinite lives + code:DDCE-C7DC + cheat + description:One hit kills, except skeletons + code:8F23-3768 + cheat + description:Mega-jump (disable to land again) + code:8F84-17D8 + cheat + description:Can't get hit - some characters are white + code:DDC7-1DD8 + cheat + description:Start with 5 lives + code:D9B8-1F04 + cheat + description:Start with 1 life + code:DFB8-1F04 + cheat + description:Start with 8 lives + code:D6B8-1F04 + cheat + description:Start with 2/3 health - 1st life + code:4DBD-CF04 + cheat + description:Start with 2/3 health - after 1st life + code:4DCE-CD0C + cheat + description:Start with 1/3 health - 1st life + code:FDBD-CF04 + cheat + description:Start with 1/3 health - after 1st life + code:FDCE-CD0C + +cartridge sha256:c509e957873d6cff232bc360ae1795ea74e86bf4fa09c686f6cfc83bd8bac3d7 + title:Dual Orb II (Japan) + cheat + description:Gain 65,535 EXP from each battle + code:CEF7-8F9F+A8F7-84FF + cheat + description:Sell one item for maximum money + code:DD4F-8FD4 + cheat + description:Can skip barrel puzzle + code:544E-7FD6 + cheat + description:No random battles + code:6D7B-77D6 + cheat + description:Enemies start with 10 HP + code:CE2C-540D+7B2C-546D + cheat + description:Enemies start with 100 HP + code:CE2C-540D + +cartridge sha256:2dfc2e037679a62a960dab9682bca6d1b2737f603edd336c8b2fdf05db10cc07 + title:Dungeon Master (USA) + cheat + description:Almost no mana loss (must have enough to cast) + code:85B5-07D9 + cheat + description:Food meter doesn't go down + code:85CF-0F29 + cheat + description:Water meter doesn't go down + code:85C5-0FB9 + cheat + description:1st character has 250 maximum hit points + code:ECDC-F26F + cheat + description:2nd character has 250 maximum hit points + code:ECDA-220F + cheat + description:3rd character has 250 maximum hit points + code:ECD3-B2D4 + cheat + description:4th character has 250 maximum hit points + code:ECDD-BAA7 + cheat + description:1st character has 250 maximum stamina + code:A0DC-F36F+DBDC-F3AF + cheat + description:2nd character has 250 maximum stamina + code:A0DA-230F+DBDA-236F + cheat + description:3rd character has 250 maximum stamina + code:A0D3-B3D4+DBD3-B304 + cheat + description:4th character has 250 maximum stamina + code:A0DD-B2A7+DBDD-B3D7 + cheat + description:1st character has 250 maximum mana + code:ECDC-FE6F + cheat + description:2nd character has 250 maximum mana + code:ECDA-2E0F + cheat + description:3rd character has 250 maximum mana + code:ECD3-BED4 + cheat + description:4th character has 250 maximum mana + code:ECDD-B3A7 + cheat + description:1st character has 99 current strength + code:17D8-F36F + cheat + description:2nd character has 99 current strength + code:17D2-230F + cheat + description:3rd character has 99 current strength + code:17DE-B3D4 + cheat + description:4th character has 99 current strength + code:17DF-B2A7 + cheat + description:1st character has 99 maximum strength + code:17D8-F30F + cheat + description:2nd character has 99 maximum strength + code:17D2-23DF + cheat + description:3rd character has 99 maximum strength + code:17DE-B2A4 + cheat + description:4th character has 99 maximum strength + code:17DF-B267 + cheat + description:1st character has 99 current dexterity + code:17D8-FE0F + cheat + description:2nd character has 99 current dexterity + code:17D2-2EDF + cheat + description:3rd character has 99 current dexterity + code:17DE-B3A4 + cheat + description:4th character has 99 current dexterity + code:17DF-B367 + cheat + description:1st character has 99 maximum dexterity + code:17D8-FEDF + cheat + description:2nd character has 99 maximum dexterity + code:17D2-23AF + cheat + description:3rd character has 99 maximum dexterity + code:17DE-B364 + cheat + description:4th character has 99 maximum dexterity + code:17DF-B307 + cheat + description:1st character has 99 current wisdom + code:17DA-FADF + cheat + description:2nd character has 99 current wisdom + code:17D2-2EAF + cheat + description:3rd character has 99 current wisdom + code:17DE-BE64 + cheat + description:4th character has 99 current wisdom + code:17DF-BE07 + cheat + description:1st character has 99 maximum wisdom + code:17D8-FEAF + cheat + description:2nd character has 99 maximum wisdom + code:17D2-2E6F + cheat + description:3rd character has 99 maximum wisdom + code:17DE-BE04 + cheat + description:4th character has 99 maximum wisdom + code:17DF-BED7 + cheat + description:1st character has 99 current vitality + code:17DA-FAAF + cheat + description:2nd character has 99 current vitality + code:17D3-2A6F + cheat + description:3rd character has 99 current vitality + code:17DD-2A04 + cheat + description:4th character has 99 current vitality + code:17D4-BAD7 + cheat + description:1st character has 99 maximum vitality + code:17DA-FA6F + cheat + description:2nd character has 99 maximum vitality + code:17D3-2A0F + cheat + description:3rd character has 99 maximum vitality + code:17DD-2AD4 + cheat + description:4th character has 99 maximum vitality + code:17DF-BEA7 + cheat + description:1st character has 99 current anti-magic + code:17DA-F26F + cheat + description:2nd character has 99 current anti-magic + code:17D3-220F + cheat + description:3rd character has 99 current anti-magic + code:17DD-22D4 + cheat + description:4th character has 99 current anti-magic + code:17D4-BAA7 + cheat + description:1st character has 99 maximum anti-magic + code:17DA-F20F + cheat + description:2nd character has 99 maximum anti-magic + code:17D3-22DF + cheat + description:3rd character has 99 maximum anti-magic + code:17DD-2AA4 + cheat + description:4th character has 99 maximum anti-magic + code:17D4-BA67 + cheat + description:1st character has 99 current anti-fire + code:17DA-F30F + cheat + description:2nd character has 99 current anti-fire + code:17D3-23DF + cheat + description:3rd character has 99 current anti-fire + code:17DD-22A4 + cheat + description:4th character has 99 current anti-fire + code:17D4-B267 + cheat + description:1st character has 99 maximum anti-fire + code:17DA-F3DF + cheat + description:2nd character has 99 maximum anti-fire + code:17D3-22AF + cheat + description:3rd character has 99 maximum anti-fire + code:17DD-2264 + cheat + description:4th character has 99 maximum anti-fire + code:17D4-B207 + cheat + description:1st character is a level 15 fighter + code:5EDA-FEAF + cheat + description:1st character is a level 15 ninja + code:5ED2-F20F + cheat + description:1st character is a level 15 healer + code:5ED2-F3AF + cheat + description:1st character is a level 15 wizard + code:5ED3-FA0F + cheat + description:2nd character is a level 15 fighter + code:5ED3-2E6F + cheat + description:2nd character is a level 15 ninja + code:5EDE-22DF + cheat + description:2nd character is a level 15 healer + code:5EDE-236F + cheat + description:2nd character is a level 15 wizard + code:5EDD-FAD4 + cheat + description:3rd character is a level 15 fighter + code:5EDD-2E04 + cheat + description:3rd character is a level 15 ninja + code:5EDF-2AA4 + cheat + description:3rd character is a level 15 healer + code:5EDF-2304 + cheat + description:3rd character is a level 15 wizard + code:5EDF-2EA4 + cheat + description:4th character is a level 15 fighter + code:5ED4-BED7 + cheat + description:4th character is a level 15 ninja + code:5ED7-BA67 + cheat + description:4th character is a level 15 healer + code:5ED7-B3D7 + cheat + description:4th character is a level 15 wizard + code:5ED7-BE67 + cheat + description:1st character has a nearly full food meter + code:D5D8-FAAF + cheat + description:1st character has a nearly full water meter + code:D5D8-F20F + cheat + description:2nd character has a nearly full food meter + code:D5D2-2A6F + cheat + description:2nd character has a nearly full water meter + code:D5D2-22DF + cheat + description:3rd character has a nearly full food meter + code:D5DE-BA04 + cheat + description:3rd character has a nearly full water meter + code:D5DE-BAA4 + cheat + description:4th character has a nearly full food meter + code:D5DF-BAD7 + cheat + description:4th character has a nearly full water meter + code:D5DF-BA67 + +cartridge sha256:8481e47381bd98c27b9782b5727a5d5f0976fbb3aa3df25c2c42aa37e0586815 + title:E.V.O. - Search for Eden (USA) + cheat + description:Invincibility + code:1D66-072B + cheat + description:Infinite EVO points + code:6D27-6FAF + cheat + description:Infinite EP + code:FDD2-FA86+45D2-FAE6 + cheat + description:Protection from most hazards + code:C96E-07FB + cheat + description:Food replenishes hit points to full + code:DD60-D18B + cheat + description:Less damage from stronger creatures + code:D566-A7F8 + cheat + description:Horn never breaks + code:C964-A726 + cheat + description:Collect one health to max it out + code:DD61-D97B + cheat + description:One-hit kills + code:DD6C-AFF2 + +cartridge sha256:0408e3d9f2259044344a3bfbd7a7ca3c3427f82108fbecd6e5c4c41e80cd303b + title:Earth Defense Force (USA) + cheat + description:Infinite shields + code:C263-6FAF + cheat + description:Infinite credits + code:C268-A491 + cheat + description:Start with 4 shields + code:7123-A4A7+3D23-A7D7 + cheat + description:Start with 5 shields + code:2B23-A4A7+B823-A7D7 + cheat + description:Start at experience level 2 + code:D42E-A7A7 + cheat + description:Start at experience level 3 + code:D72E-A7A7 + cheat + description:Start at experience level 4 + code:D02E-A7A7 + cheat + description:Start at experience level 5 + code:D92E-A7A7 + cheat + description:Advancing experience levels is easier + code:4D21-6F0F + cheat + description:Advancing experience levels is much easier + code:DA21-6F0F + cheat + description:2 credits + code:DF2E-AF67+CB2E-AF07+DD2E-AFA7 + cheat + description:3 credits + code:D42E-AF67+CB2E-AF07+DD2E-AFA7 + cheat + description:6 credits + code:D92E-AF67+CB2E-AF07+DD2E-AFA7 + cheat + description:8 credits + code:D52E-AF67+CB2E-AF07+DD2E-AFA7 + cheat + description:10 credits + code:DB2E-AF67+CB2E-AF07+DD2E-AFA7 + cheat + description:1 credit + code:DD2E-AF67+CB2E-AF07+DD2E-AFA7 + cheat + description:Keep current score when game is continued + code:C223-AFD7+C223-AFA7 + cheat + description:Start at stage 2 + code:DF37-DDDD+CB34-D7AD+DD37-DD0D + cheat + description:Start at stage 3 + code:D437-DDDD+CB34-D7AD+DD37-DD0D + cheat + description:Start at stage 4 + code:D737-DDDD+CB34-D7AD+DD37-DD0D + cheat + description:Start at stage 5 + code:D037-DDDD+CB34-D7AD+DD37-DD0D + cheat + description:Start at stage 6 + code:D937-DDDD+CB34-D7AD+DD37-DD0D + +cartridge sha256:a8fe2226728002786d68c27ddddf0b90a894db52e4dfe268fdf72a68cae5f02e + title:EarthBound (USA) + cheat + description:Infinite health (all characters) + code:8251-57D6 + cheat + description:Get to level 99 after one battle (all characters) + code:EE2E-54A1 + cheat + description:Fast money (buy a bread w/the code off, turn code on and sell it for $32,646) + code:EE9A-E5F5 + cheat + description:Start with a level 9 character + code:DB23-77D1 + cheat + description:Start with a level 15 character + code:DE23-77D1 + cheat + description:Start with a level 50 character + code:7423-77D1 + cheat + description:Start with a level 100 character + code:1723-77D1 + cheat + description:Start with a level 255 character + code:EE23-77D1 + cheat + description:Start with a super strong character + code:EE2E-7D01 + cheat + description:Start with a lot of HP + code:BB2D-5461 + cheat + description:Start with a lot of PSI + code:BB2F-54A1 + cheat + description:Dad never calls + code:E395-87DD + cheat + description:Infinite health + code:7E9A13:E7+7E9A14:03 + cheat + description:9999 current PP + code:7E9A1B:0F+7E9A1C:27 + +cartridge sha256:4579e437279f79eedd6b9cf648a814df2ab2c83d937a1bcec1578d28965fb9a0 + title:Earthworm Jim (USA) + cheat + description:Infinite health + code:A21F-7464 + cheat + description:Infinite Ammo + code:2215-EFAF + cheat + description:Infinite lives + code:A2DA-87A7 + cheat + description:Die after one hit + code:7D17-7F64 + cheat + description:Start with 1 life + code:7D13-8FDF + cheat + description:Start with 5 lives + code:7013-8FDF + cheat + description:Start with 10 lives + code:7B13-8FDF + cheat + description:Start with 25 lives + code:0613-8FDF + cheat + description:Start with 50 lives + code:1F13-8FDF + cheat + description:Start with 300% health + code:7717-7F64 + cheat + description:Start with 500% health + code:7917-7F64 + cheat + description:Start with 900% health + code:7B17-7F64 + cheat + description:Invincibility against enemies + code:7E682A:3D + cheat + description:Infinite health (alt) + code:7E6627:39 + cheat + description:Infinite shields + code:7E6B48:63 + cheat + description:Super shot always active + code:7E661C:FF+7E69A0:09 + cheat + description:Infinite time in Sub + code:7E6752:63 + cheat + description:Always win race in Andy Asteroids stages (glitchy graphics) + code:7E6B46:FF + cheat + description:Start on What The Heck? + code:7E512A:01 + cheat + description:Start on What The Heck? (Snowman Boss) + code:7E512A:02 + cheat + description:Start on What The Heck? (Boss Fight With Evil The Cat) + code:7E512A:03 + cheat + description:Start on Snot A Problem Round 1 + code:7E512A:04 + cheat + description:Start on Snot A Problem Round 2 + code:7E512A:05 + cheat + description:Start on Snot A Problem Round 3 + code:7E512A:06 + cheat + description:Start on For Pete's Sake + code:7E512A:07 + cheat + description:Start on Buttville, Part 2 + code:7E512A:08 + cheat + description:Start on Buttville, Part 1 + code:7E512A:09 + cheat + description:Start on Level 5, Part 1 + code:7E512A:0A + cheat + description:Start on Level 5 (Chicken Boss) + code:7E512A:0B + cheat + description:Start on Level 5, Part 2 + code:7E512A:0C + cheat + description:Start on Down The Tubes + code:7E512A:0D + cheat + description:Start on Tube Race + code:7E512A:0E + cheat + description:Start on Andy Asteroids?, Course 1 + code:7E512A:0F + cheat + description:Start on Andy Asteroids?, Course 2 + code:7E512A:10 + cheat + description:Start on Andy Asteroids?, Course 3 + code:7E512A:11 + cheat + description:Start on Andy Asteroids?, Course 4 + code:7E512A:12 + cheat + description:Start on Andy Asteroids?, Course 5 + code:7E512A:13 + cheat + description:Start on Andy Asteroids?, Course 6 + code:7E512A:14 + cheat + description:Start on Who Turned Out The Light?, Part 1 + code:7E512A:15 + cheat + description:Start on Who Turned Out The Light?, Part 2 + code:7E512A:16 + cheat + description:Start on Who Turned Out The Light?, Part 3 + code:7E512A:17 + cheat + description:Start on Who Turned Out The Light?, Part 4 + code:7E512A:18 + cheat + description:Start on Who Turned Out The Light?, Part 5 + code:7E512A:19 + cheat + description:Start on Psycrow + code:7E512A:1A + +cartridge sha256:10eadaab168707829418702386e1bcedd2619d9bbefc37cf31c4118313bcf6de + title:Earthworm Jim 2 (USA) + cheat + description:Infinite health + code:CB57-7D0B + cheat + description:Infinite lives + code:CBF0-7464 + cheat + description:Get 1000 bullets on pick-up + code:D798-74F7+3B98-7F27 + cheat + description:Get 2000 bullets on pick-up + code:D598-74F7+3D98-7F27 + cheat + description:Start with 200% health + code:7450-770B + cheat + description:Start with 300% health + code:7750-770B + cheat + description:Start with 400% health + code:7050-770B + cheat + description:Start with 500% health + code:7950-770B + cheat + description:Start with 700% health + code:7550-770B + cheat + description:Start with 900% health + code:7B50-770B + cheat + description:Start with 1 life and no continues + code:7D55-5F06 + cheat + description:Start with 5 lives + code:7055-5F06 + cheat + description:Start with 7 lives + code:7155-5F06 + cheat + description:Start with 9 lives + code:7655-5F06 + cheat + description:Start with 2000 bullets + code:749E-54B4 + cheat + description:Start with 3000 bullets + code:779E-54B4 + cheat + description:Start with 4000 bullets + code:709E-54B4 + cheat + description:Start with 5000 bullets + code:799E-54B4 + cheat + description:Start with 7000 bullets + code:759E-54B4 + cheat + description:Start with 9000 bullets + code:7B9E-54B4 + cheat + description:Invincibility + code:7E653C:10 + +cartridge sha256:5d658b63d35e2e0baf48ae3bb04ea5e1553855b34bb39fc2c7ca41fbd3894d52 + title:Eek! The Cat (USA) + cheat + description:Infinite health + code:7E004E:BF + cheat + description:Infinite lives + code:7E1FE5:09 + +cartridge sha256:a6eec3329d956e1ddc4acfe3c738387622c10fc95fb9ab63dd5f45be8bec0b16 + title:Emerald Dragon (Japan) + cheat + description:Max level after one battle + code:6DDA-E707 + cheat + description:Max Parus after one battle + code:6DD6-E4D7 + cheat + description:No random battles + code:F6C0-57D0 + +cartridge sha256:cfd666f0bbabec59613d9fe189db7d0a060a78047bc084c0c365840769047bf2 + title:Equinox (USA) + cheat + description:Invincibility against most small monsters + code:C28F-AF4D + cheat + description:Infinite life + code:3CA0-0DC7 + cheat + description:Infinite magic (must have enough MP for spell to work) + code:CEAE-0D17 + cheat + description:More life from Apples + code:CB2A-C4D9 + cheat + description:Super-jump + code:4F27-1F00+4020-1FD0 + cheat + description:Mega-jump + code:FC27-1F00+4020-1FD0 + cheat + description:Super speed + code:B32C-4FA0+CD2C-4700 + cheat + description:Colored doors don't need keys + code:DD86-674F+3C86-671F + cheat + description:Slow spell lasts 2x as long + code:D9AC-6437 + cheat + description:Slow spell lasts 3x as long + code:D6AC-6437 + cheat + description:Freeze spell lasts 2x as long + code:D9AB-6FC7 + cheat + description:Freeze spell lasts 3x as long + code:D6AB-6FC7 + +cartridge sha256:1576066e0cb771a91caf79e7d4f6dc00eb0daa47f0786f1604b32537429a7f45 + title:Extra Innings (USA) + cheat + description:Game lasts 1 inning + code:DFBE-ADAD+DFBF-DF6F+DFB4-0FDF + cheat + description:Game lasts 2 innings + code:D4BE-ADAD+D4BF-DF6F+D4B4-0FDF + cheat + description:Game lasts 3 innings + code:D7BE-ADAD+D7BF-DF6F+D7B4-0FDF + cheat + description:Game lasts 4 innings + code:D0BE-ADAD+D0BF-DF6F+D0B4-0FDF + cheat + description:Game lasts 5 innings + code:D9BE-ADAD+D9BF-DF6F+D9B4-0FDF + cheat + description:Game lasts 7 innings + code:D5BE-ADAD+D5BF-DF6F+D5B4-0FDF + cheat + description:1 strike and batter's out + code:DF67-DF07+DD60-A4D7 + cheat + description:2 strikes and batter's out + code:D467-DF07+DF60-A4D7 + cheat + description:Batter never strikes out + code:C264-D767+C260-A4A7 + cheat + description:1 ball and batter walks + code:DF6A-DFA7 + cheat + description:2 balls and batter walks + code:D46A-DFA7 + cheat + description:3 balls and batter walks + code:D76A-DFA7 + cheat + description:Batter never walks + code:C26A-DDD7 + cheat + description:1 out per inning + code:DF67-AD67+DF61-D4A7 + cheat + description:2 outs per inning + code:D467-AD67+D461-D4A7 + +cartridge sha256:0a8cd5101f849ccd4e40d55fdc4edce914b2825b69eb76ec31cf53b59719e79e + title:Eye of the Beholder (USA) + cheat + description:Infinite HP + code:8285-6D2C+82DE-049B + cheat + description:No waiting to hit again + code:828D-A798 + cheat + description:One hit kills (works for enemies also) + code:CBAA-A726+3CA2-AD96 + cheat + description:Pick a lawful, human male fighter and he will be at Level 8 + code:D68B-A474 + cheat + description:Pick a lawful, human male fighter and he will be at level 6 + code:D18B-A474 + cheat + description:999,999 EXP 1st class + code:7E0533:3F+7E0534:42+7E0535:0F + +cartridge sha256:1d38e3af9e3a6409e93f4705b68c42558f558c68f3e83ef2a40e46cf560b26cc + title:F1 ROC - Race of Champions (USA) + cheat + description:No damage when hitting walls + code:C9A8-07DD + cheat + description:No damage when hitting other cars + code:C922-0FDD + cheat + description:Normal tires are free + code:DDEE-6F21 + cheat + description:Hi-grip tires are free + code:DDEE-6491 + cheat + description:Rain tires are free + code:DDEE-6F91 + cheat + description:2L nitro is free + code:DDED-A491 + cheat + description:3L nitro is free + code:DDED-A421 + cheat + description:4L nitro is free + code:DDED-A791 + cheat + description:Ford V-8 engine is free + code:DDEE-6721+DDED-ADF1 + cheat + description:Ilmoa V-8 engine is free + code:DDED-AD91+DDED-ADB1 + cheat + description:Remart V-10 engine is free + code:DDED-AD21+DDED-AFF1 + cheat + description:Low DF rear wing is free + code:DDE3-6791 + cheat + description:High DF rear wing is free + code:DDEE-6D91+DDEE-6DB1 + cheat + description:Low DF front wing is free + code:DDE3-6D21 + cheat + description:High DF front wing is free + code:DDE3-6F21+DDE3-64F1 + cheat + description:Special-L front wing is free + code:DDE3-6491+DDE3-64B1 + cheat + description:Small diffuser is free + code:DDE2-6421 + cheat + description:Large diffuser is free + code:DDE2-6721 + cheat + description:Special diffuser is free + code:DDE3-6D91+DDE3-6DB1 + cheat + description:Hard suspension is free + code:DDE2-6F21 + cheat + description:Active suspension is free + code:DDE2-6491+DDE2-64B1 + cheat + description:Carbon brakes are free + code:DDE2-6D91 + cheat + description:Antilock brakes are free + code:DDE2-6D21+DDE2-6FF1 + cheat + description:5-speed transmission is free + code:DDEA-6491 + cheat + description:6-speed transmission is free + code:DDEA-6421+DDEA-67F1 + cheat + description:7-speed transmission is free + code:DDEA-6791+DDEA-67B1 + cheat + description:Type 2 chassis is free + code:DDEA-6D21+DDEA-6FF1 + cheat + description:Type 3 chassis is free + code:DDEA-6F91+DDEA-6FB1 + cheat + description:Start with no money instead of $500 + code:BA26-A44F + cheat + description:Start with $5,240 + code:3C26-AF4F+CB26-AF1F+D426-AF3F + cheat + description:Start with $20,600 + code:3C26-AF4F+CB26-AF1F+D626-AF3F + cheat + description:Start with $163,960 + code:3C26-AF4F+CB26-AF1F+0D26-AF3F + cheat + description:Start with $327,800 + code:3C26-AF4F+CB26-AF1F+6D26-AF3F + cheat + description:Start with $652,920 + code:3C26-AF4F+CB26-AF1F+EE26-AF3F + +cartridge sha256:d689392884df91c2bb84b1411a96f3919b6c9cc8a583dff901a98f0d86d31c30 + title:Faceball 2000 (USA) + cheat + description:Infinite lives + code:89AB-D708 + cheat + description:Only need 8 tags to win in arena mode instead of 10 (start with 2 instead of 0) + code:B9B1-6F01 + cheat + description:Allow 98 seconds in zone 1 bonus level + code:1061-DD52 + cheat + description:Allow 98 seconds in zone 2 bonus level + code:1069-6752 + cheat + description:Allow 98 seconds in zone 3 bonus level + code:1068-DDE3 + cheat + description:Allow 98 seconds in zone 4 bonus level + code:1061-A473 + cheat + description:Allow 198 seconds in zone 5 bonus level + code:A66C-047E + cheat + description:Allow 198 seconds in zone 6 bonus level + code:A6B1-D45A + cheat + description:Allow 198 seconds in zone 7 bonus level + code:A6B0-AF7A + cheat + description:Start with 1 life instead of 3 + code:DFB6-6461 + cheat + description:Start with 5 lives + code:D9B6-6461 + cheat + description:Start with 7 lives + code:D5B6-6461 + cheat + description:Start with 9 lives + code:DBB6-6461 + cheat + description:Start with 25 lives + code:FBB6-6461 + cheat + description:Start with 50 lives + code:74B6-6461 + cheat + description:Start with 75 lives + code:08B6-6461 + cheat + description:Start with 99 lives + code:17B6-6461 + cheat + description:Start with 255 lives + code:EEB6-6461 + cheat + description:Start each Cyberzone level with 1 tag required + code:CBB5-6406+DFB5-6466 + cheat + description:Start each Cyberzone level with 5 tags required + code:CBB5-6406+D9B5-6466 + cheat + description:Start each Cyberzone level with 20 tags required + code:CBB5-6406+F0B5-6466 + cheat + description:Start each Cyberzone level with 30 tags required + code:CBB5-6406+F3B5-6466 + cheat + description:Start each Cyberzone level with 60 tags required + code:CBB5-6406+7AB5-6466 + cheat + description:Start each Cyberzone level with 90 tags required + code:CBB5-6406+9CB5-6466 + cheat + description:Start Cyberzone mode on zone 1 level 2 + code:C282-0706+DFCE-0468 + cheat + description:Start Cyberzone mode on zone 1 level 3 + code:C282-0706+D4CE-0468 + cheat + description:Start Cyberzone mode on zone 1 level 4 + code:C282-0706+D7CE-0468 + cheat + description:Start Cyberzone mode on zone 1 level 5 + code:C282-0706+D0CE-0468 + cheat + description:Start Cyberzone mode on zone 1 bonus level + code:C282-0706+D9CE-0468 + cheat + description:Start Cyberzone mode on zone 2 level 6 + code:C282-0706+D1CE-0468 + cheat + description:Start Cyberzone mode on zone 2 level 7 + code:C282-0706+D5CE-0468 + cheat + description:Start Cyberzone mode on zone 2 level 8 + code:C282-0706+D6CE-0468 + cheat + description:Start Cyberzone mode on zone 2 level 9 + code:C282-0706+DBCE-0468 + cheat + description:Start Cyberzone mode on zone 2 level 10 + code:C282-0706+DCCE-0468 + cheat + description:Start Cyberzone mode on zone 2 bonus level + code:C282-0706+D8CE-0468 + cheat + description:Start Cyberzone mode on zone 3 level 11 + code:C282-0706+DACE-0468 + cheat + description:Start Cyberzone mode on zone 3 level 12 + code:C282-0706+D2CE-0468 + cheat + description:Start Cyberzone mode on zone 3 level 13 + code:C282-0706+D3CE-0468 + cheat + description:Start Cyberzone mode on zone 3 level 14 + code:C282-0706+DECE-0468 + cheat + description:Start Cyberzone mode on zone 3 level 15 + code:C282-0706+FDCE-0468 + cheat + description:Start Cyberzone mode on zone 3 bonus level + code:C282-0706+FFCE-0468 + cheat + description:Start Cyberzone mode on zone 4 level 16 + code:C282-0706+F4CE-0468 + cheat + description:Start Cyberzone mode on zone 4 level 17 + code:C282-0706+F7CE-0468 + cheat + description:Start Cyberzone mode on zone 4 level 18 + code:C282-0706+F0CE-0468 + cheat + description:Start Cyberzone mode on zone 4 level 19 + code:C282-0706+F9CE-0468 + cheat + description:Start Cyberzone mode on zone 4 level 20 + code:C282-0706+F1CE-0468 + cheat + description:Start Cyberzone mode on zone 4 bonus level + code:C282-0706+F5CE-0468 + cheat + description:Start Cyberzone mode on zone 5 level 21 + code:C282-0706+F6CE-0468 + cheat + description:Start Cyberzone mode on zone 5 level 22 + code:C282-0706+FBCE-0468 + cheat + description:Start Cyberzone mode on zone 5 level 23 + code:C282-0706+FCCE-0468 + cheat + description:Start Cyberzone mode on zone 5 level 24 + code:C282-0706+F8CE-0468 + cheat + description:Start Cyberzone mode on zone 5 level 25 + code:C282-0706+FACE-0468 + cheat + description:Start Cyberzone mode on zone 5 bonus level + code:C282-0706+F2CE-0468 + cheat + description:Start Cyberzone mode on zone 6 level 26 + code:C282-0706+F3CE-0468 + cheat + description:Start Cyberzone mode on zone 6 level 27 + code:C282-0706+FECE-0468 + cheat + description:Start Cyberzone mode on zone 6 level 28 + code:C282-0706+4DCE-0468 + cheat + description:Start Cyberzone mode on zone 6 level 29 + code:C282-0706+4FCE-0468 + cheat + description:Start Cyberzone mode on zone 6 level 30 + code:C282-0706+44CE-0468 + cheat + description:Start Cyberzone mode on zone 6 bonus level + code:C282-0706+47CE-0468 + cheat + description:Start Cyberzone mode on zone 7 level 31 + code:C282-0706+40CE-0468 + cheat + description:Start Cyberzone mode on zone 7 level 32 + code:C282-0706+49CE-0468 + cheat + description:Start Cyberzone mode on zone 7 level 33 + code:C282-0706+41CE-0468 + cheat + description:Start Cyberzone mode on zone 7 level 34 + code:C282-0706+45CE-0468 + cheat + description:Start Cyberzone mode on zone 7 level 35 + code:C282-0706+46CE-0468 + cheat + description:Start Cyberzone mode on zone 7 bonus level + code:C282-0706+4BCE-0468 + cheat + description:Start Cyberzone mode on zone 8 level 36 + code:C282-0706+4CCE-0468 + cheat + description:Start Cyberzone mode on zone 8 level 37 + code:C282-0706+48CE-0468 + cheat + description:Start Cyberzone mode on zone 8 level 38 + code:C282-0706+4ACE-0468 + cheat + description:Start Cyberzone mode on zone 8 level 39 + code:C282-0706+42CE-0468 + cheat + description:Start Cyberzone mode on zone 8 level 40 + code:C282-0706+43CE-0468 + cheat + description:Start Cyberzone mode on zone 8 level 41 + code:C282-0706+4ECE-0468 + +cartridge sha256:2891f1eab285133364ecc379a5c9e1d0026d60f425f1a458d149014f386cfa50 + title:Family Dog (USA) + cheat + description:Infinite health (except against vacuum or falls) + code:82C6-37D5 + cheat + description:Infinite lives + code:C2A8-C7D9 + cheat + description:Infinite Super Barks + code:C2AE-CD69 + cheat + description:Start with 90 Super Barks + code:DB6F-17AD + cheat + description:Cheese Treats worth 10 Super Barks + code:DCA2-CDA9 + cheat + description:Start in the Hallway + code:9DA0-CF67 + cheat + description:Start in the Living Room + code:10A0-CF67 + cheat + description:Start in the Hallway to the Kitchen + code:13A0-CF67 + cheat + description:Start in the Kitchen + code:64A0-CF67 + cheat + description:Start in the Hallway to the Backdoor + code:6AA0-CF67 + cheat + description:Start outside the Yard + code:B1A0-CF67 + cheat + description:Start in the Kennel Interior + code:83A0-CF67 + cheat + description:Start in the Kennel Exterior + code:3DA0-CF67+DFA0-CFA7 + cheat + description:Start in the Woods and Trees + code:E0A0-CF67+DFA0-CFA7 + cheat + description:View the ending + code:FAA0-CF67+D4A0-CFA7 + +cartridge sha256:c92f389d25870aada3002775838ec9f69a988120c0238af885fd08d46bd94930 + title:Fatal Fury (USA) + cheat + description:Take minimum damage - P1 + code:C2A9-D40F + cheat + description:Take minimum damage - P2/CPU + code:C2A2-DF6F + cheat + description:Win 1 bout to win the match instead of 2 out of 3 (disable on bonus rounds) + code:DFA5-64DF + cheat + description:10 seconds to complete bonus rounds + code:FDC7-AFAF + cheat + description:30 seconds to complete bonus rounds + code:7DC7-AFAF + cheat + description:45 seconds to complete bonus rounds + code:09C7-AFAF + cheat + description:60 seconds to complete bonus rounds + code:1DC7-AFAF + cheat + description:90 seconds to complete bonus rounds + code:BDC7-AFAF + cheat + description:Always fight Richard Myer on the West Subway + code:BAB4-6DAD+D7BC-A46D + cheat + description:Always fight Michael Max on the West Subway + code:BAB4-6DAD+D0BC-A46D + cheat + description:Always fight Duck King on the West Subway + code:BAB4-6DAD+D9BC-A46D + cheat + description:Always fight Tung Fu Rue on the West Subway + code:BAB4-6DAD+D1BC-A46D + cheat + description:Always fight Hwa Jai on the West Subway + code:BAB4-6DAD+D5BC-A46D + cheat + description:Always fight Raiden on the West Subway + code:BAB4-6DAD+D6BC-A46D + cheat + description:Always fight Billy Kane on the West Subway + code:BAB4-6DAD+DBBC-A46D + cheat + description:Always fight Geese Howard on the West Subway + code:BAB4-6DAD+DCBC-A46D + cheat + description:Start with 1/4 health - both players + code:F6CD-A4AF + cheat + description:Start with 1/2 health - both players + code:7DCD-A4AF + cheat + description:Start with 3/4 health - both players + code:06CD-A4AF + +cartridge sha256:a0c554d46034caef231c36dd6849828ca39703678fb7fdd15a11f292b93bcd6b + title:Fatal Fury 2 (USA) + cheat + description:Infinite health - P1 + code:6D7D-54AD + cheat + description:Infinite time + code:DD7E-7FDD + cheat + description:Timer is 2x fast + code:D47E-7FDD + cheat + description:Timer is 3x fast + code:D77E-7FDD + cheat + description:Computer can't win a round, except last round, game ends after 4 rounds + code:C250-7FA7 + cheat + description:P1 is Billy Kane + code:CB85-E40F+D685-E46F+DD85-E4AF + cheat + description:P1 is Axel Hawk + code:DB85-E46F+CB85-E40F+DD85-E4AF + cheat + description:P1 is Lawrence B + code:CB85-E40F+DD85-E4AF+DC85-E46F + cheat + description:P1 is Wolfgang Krauser + code:D885-E46F+CB85-E40F+DD85-E4AF + cheat + description:P2 is Billy Kane + code:CB82-E40F+D682-E46F+DD82-E4AF + cheat + description:P2 is Axel Hawk + code:DB82-E46F+CB82-E40F+DD82-E4AF + cheat + description:P2 is Lawrence B + code:DC82-E46F+CB82-E40F+DD82-E4AF + cheat + description:P2 is Wolfgang Krauser + code:D882-E46F+CB82-E40F+DD82-E4AF + cheat + description:Super vertical jump - P1 + code:FDD5-EFCB + cheat + description:Bogus vertical jump - P1 + code:EED5-EFCB + cheat + description:Start with 1/2 health + code:7D78-770D + +cartridge sha256:410e90db3d38507ccc85ad3bca6b27a080123fd5160e82b5de4d914d4b6d6e61 + title:Fatal Fury Special (USA) + cheat + description:Instant win - P1 + code:7FF9FD:00 + cheat + description:Almost infinite time + code:7FFCC1:63 + cheat + description:Win 1 round to win the match - P1 + code:7FFC49:02 + cheat + description:Play as Ryo Sakazaki + code:7FF703:0F + +cartridge sha256:b9594d588816ae570ea5fea14577ed47de4db9ac9a40a116c84e0ad7a2ce58f8 + title:Fighter's History (USA) (Rev 1) + cheat + description:Infinite health - P1 + code:7E0A56:C8 + +cartridge sha256:f71817f55febd32fd1dce617a326a77b6b062dd0d4058ecd289f64af1b7a1d05 + title:Final Fantasy - Mystic Quest (USA) (Rev 1) + cheat + description:Infinite cure potions + code:83AF-D40D + cheat + description:Use a cure, gain a cure + code:E3AF-D40D + cheat + description:Gain 198 cures after one is used + code:03AF-D40D + cheat + description:Cure restores life points to maximum + code:DDA4-D40D + cheat + description:Infinite life points - can make enemies invincible + code:C96B-64AB + cheat + description:Infinite ninja stars + code:C9B8-D4A6 + cheat + description:Infinite bombs in battle + code:C9B0-D7A6 + cheat + description:Quick level gain + code:6D2A-DD8D + cheat + description:Infinite Cure potions + code:7E0E9E:10+7E0E9F:62 + cheat + description:Infinite Heal potions + code:7E0EA0:10+7E0EA1:62 + cheat + description:Infinite Seeds + code:7E0EA2:10+7E0EA3:62 + cheat + description:Infinite GP + code:7E0E86:97 + cheat + description:Have most items + code:7E0EA6:FE+7E0EA7:7F + cheat + description:Have all weapons + code:7E1032:FF+7E1033:FF + cheat + description:Have all spells + code:7E1038:FF+7E1039:FF + cheat + description:Cure potions restore full health + code:00A040:44+15C049:D5 + cheat + description:99 items in row 1 slot 1 + code:7E0E9F:63 + cheat + description:99 items in row 1 slot 2 + code:7E0E91:63 + cheat + description:99 items in row 1 slot 3 + code:7E0E93:63 + cheat + description:Character 1 - 9999 HP + code:7E1014:0F+7E1015:27 + cheat + description:Character 1 - 9999 maximum HP + code:7E1016:0F+7E1017:27 + cheat + description:Character 1 - max level + code:7E1010:29 + cheat + description:Character 1 - max experience + code:7E1011:7F+7E1012:96+7E1013:98 + cheat + description:Character 1 - 99 White MP + code:7E1018:63 + cheat + description:Character 1 - 99 maximum White MP + code:7E101B:63 + cheat + description:Character 1 - 99 Black MP + code:7E1019:63 + cheat + description:Character 1 - 99 maximum Black MP + code:7E101C:63 + cheat + description:Character 1 - 99 Wizard MP + code:7E101A:63 + cheat + description:Character 1 - 99 maximum Wizard MP + code:7E101D:63 + cheat + description:Character 1 - Infinite Bombs + code:7E1030:63 + cheat + description:Character 1 - Have Sword level 3 + code:7E1031:22 + cheat + description:Character 1 - Have Axe level 3 + code:7E1031:25 + cheat + description:Character 1 - Have Claw level 3 + code:7E1031:28 + cheat + description:Character 1 - Have Bombs level 3 + code:7E1031:2B + cheat + description:Character 2 - 9999 HP + code:7E1096:0F+7E1097:27 + cheat + description:Character 2 - 99 White MP + code:7E1098:63 + cheat + description:Character 2 - 99 maximum White MP + code:7E109B:63 + cheat + description:Character 2 - 99 Black MP + code:7E1099:63 + cheat + description:Character 2 - 99 maximum Black MP + code:7E109C:63 + cheat + description:Character 2 - 99 Wizard MP + code:7E109A:63 + cheat + description:Character 2 - 99 maximum Wizard MP + code:7E109D:63 + cheat + description:Character 2 - Infinite weapon + code:7E10B0:62 + cheat + description:Character 2 - Have Sword level 3 + code:7E10B1:22 + cheat + description:Character 2 - Have Axe level 3 + code:7E10B1:25 + cheat + description:Character 2 - Have Claw level 3 + code:7E10B1:28 + cheat + description:Character 2 - Have Bombs level 3 + code:7E10B1:2B + cheat + description:Character 2 - Have Bow And Arrows + code:7E10B1:2D + cheat + description:Character 2 - Have Throwing Star + code:7E10B1:2E + +cartridge sha256:6151389f33ce2e53db3cd99592440c0020f5f4668f581ce3bd615bc92077f255 + title:Final Fantasy - Mystic Quest (USA) + cheat + description:Infinite life points (can make enemies invincible, disable to defeat them) + code:C96B-64AB + cheat + description:Infinite cure potions + code:83AF-D40D + cheat + description:Infinite ninja stars + code:C9B8-D4A6 + cheat + description:Infinite bombs in battle + code:C9B0-D7A6 + cheat + description:Use a cure, gain a cure + code:E3AF-D40D + cheat + description:Gain 198 cures after one is used + code:03AF-D40D + cheat + description:Cure restores life points to maximum + code:DDA4-D40D + cheat + description:Quick level gain + code:6D2A-DD8D + cheat + description:Infinite Cure potions + code:7E0E9E:10+7E0E9F:62 + cheat + description:Infinite Heal potions + code:7E0EA0:10+7E0EA1:62 + cheat + description:Infinite Seeds + code:7E0EA2:10+7E0EA3:62 + cheat + description:Infinite GP + code:7E0E86:97 + cheat + description:Have most items + code:7E0EA6:FE+7E0EA7:7F + cheat + description:Have all weapons + code:7E1032:FF+7E1033:FF + cheat + description:Have all spells + code:7E1038:FF+7E1039:FF + cheat + description:Cure potions restore full health + code:00A040:44+15C049:D5 + cheat + description:99 items in row 1 slot 1 + code:7E0E9F:63 + cheat + description:99 items in row 1 slot 2 + code:7E0E91:63 + cheat + description:99 items in row 1 slot 3 + code:7E0E93:63 + cheat + description:Character 1 - 9999 HP + code:7E1014:0F+7E1015:27 + cheat + description:Character 1 - 9999 maximum HP + code:7E1016:0F+7E1017:27 + cheat + description:Character 1 - max level + code:7E1010:29 + cheat + description:Character 1 - max experience + code:7E1011:7F+7E1012:96+7E1013:98 + cheat + description:Character 1 - 99 White MP + code:7E1018:63 + cheat + description:Character 1 - 99 maximum White MP + code:7E101B:63 + cheat + description:Character 1 - 99 Black MP + code:7E1019:63 + cheat + description:Character 1 - 99 maximum Black MP + code:7E101C:63 + cheat + description:Character 1 - 99 Wizard MP + code:7E101A:63 + cheat + description:Character 1 - 99 maximum Wizard MP + code:7E101D:63 + cheat + description:Character 1 - Infinite Bombs + code:7E1030:63 + cheat + description:Character 1 - Have Sword level 3 + code:7E1031:22 + cheat + description:Character 1 - Have Axe level 3 + code:7E1031:25 + cheat + description:Character 1 - Have Claw level 3 + code:7E1031:28 + cheat + description:Character 1 - Have Bombs level 3 + code:7E1031:2B + cheat + description:Character 2 - 9999 HP + code:7E1096:0F+7E1097:27 + cheat + description:Character 2 - 99 White MP + code:7E1098:63 + cheat + description:Character 2 - 99 maximum White MP + code:7E109B:63 + cheat + description:Character 2 - 99 Black MP + code:7E1099:63 + cheat + description:Character 2 - 99 maximum Black MP + code:7E109C:63 + cheat + description:Character 2 - 99 Wizard MP + code:7E109A:63 + cheat + description:Character 2 - 99 maximum Wizard MP + code:7E109D:63 + cheat + description:Character 2 - Infinite weapon + code:7E10B0:62 + cheat + description:Character 2 - Have Sword level 3 + code:7E10B1:22 + cheat + description:Character 2 - Have Axe level 3 + code:7E10B1:25 + cheat + description:Character 2 - Have Claw level 3 + code:7E10B1:28 + cheat + description:Character 2 - Have Bombs level 3 + code:7E10B1:2B + cheat + description:Character 2 - Have Bow And Arrows + code:7E10B1:2D + cheat + description:Character 2 - Have Throwing Star + code:7E10B1:2E + +cartridge sha256:414bacc05a18a6137c0de060b4094ab6d1b75105342b0bb36a42e45d945a0e4d + title:Final Fantasy II (USA) (Rev 1) + cheat + description:Almost infinite HP (can make big and sometimes normal monsters invincible, disable to defeat them) + code:82AE-6F63 + cheat + description:Infinite MP during battles, doesn't work on twin attacks + code:8267-0D62 + cheat + description:Infinite items outside of battle except for the Whistle + code:C3CE-6F09 + cheat + description:Infinite Whistles + code:C3C4-A4D0 + cheat + description:Money doesn't decrease if you run away from a battle + code:C262-DF03+C262-D763 + cheat + description:Money doesn't decrease in shops + code:C2AD-AD69+C3AD-AFA9 + cheat + description:No random battles + code:DDD6-B28B + cheat + description:No random battles (alt) + code:1D60-0704 + cheat + description:Always fight the rarest enemy in that area + code:DA6E-6FD4 + cheat + description:Always get a treasure from each enemy defeated + code:6D3E-DD0E + cheat + description:When treasures are awarded after battle, receive 5 instead of 1 + code:D926-D4D9 + cheat + description:When arrows are awarded after battle, receive 50 instead of 10 + code:7425-D769 + cheat + description:When treasures are awarded after battle, receive the rarest + code:D737-0F0E + cheat + description:Sumon the Big Chocobo anywhere by using a Carrot instead of the Whistle + code:38C4-AF00 + cheat + description:The quantity of items don't decrease when selling them + code:82A9-6FD1 + cheat + description:No music while traveling or in a town + code:1D67-A7A4 + cheat + description:Gunslinger code + code:00CE-6D69 + cheat + description:Save anywhere + code:CBBA-07A4 + cheat + description:Get at least 150 GP after each battle + code:1B35-0D6E+B135-0DAE+3C35-0FDE + cheat + description:Get at least 255 GP after each battle + code:3335-076E + cheat + description:Get at least 65,536 GP after each battle + code:3336-0FAE + cheat + description:Get 99 of items that you are given or find in a pot, treasure chest, ect + code:17BF-D404 + cheat + description:Get 99 arrows when you find them in a pot or treasure chest + code:17B4-D4D4 + cheat + description:Cure2 is ultra strong + code:A6B7-A4E2 + cheat + description:Cure2 restores HP to all members in the party during battle + code:0DB7-A482 + cheat + description:Cure2 restores all HP/MP during battle + code:F1B7-A752 + cheat + description:Fire1 spell is ultra strong + code:A6B0-D7E3 + cheat + description:Fire1 spell hits every enemy + code:AFB0-D783 + cheat + description:Ice1 spell is ultra strong + code:A6B1-DD53 + cheat + description:Ice1 spell hits every enemy + code:AFB1-DD73 + cheat + description:Lit1 spell is ultra strong + code:A6B5-DDE3 + cheat + description:Lit1 spell hits every enemy + code:AFB5-DD83 + cheat + description:Automatically win battles (no EXP or gold gained) + code:7E1801:02+7E1800:08 + cheat + description:65,000+ exp points after each battle + code:7E3592:FF+7E359E:FF + cheat + description:Character 1 - Max HP + code:7E1047:0F+7E1048:27+7E1049:0F+7E104A:27 + cheat + description:Character 1 - Max MP + code:7E104B:0F+7E104C:27+7E104D:0F+7E104E:27 + cheat + description:Character 1 - Max Agility + code:7E1050:63+7E1055:63 + cheat + description:Character 1 - Max Strength + code:7E104F:63+7E1054:63 + cheat + description:Character 1 - Max Vitality + code:7E1051:63+7E1056:63 + cheat + description:Character 1 - Max Will + code:7E1053:63+7E1058:63 + cheat + description:Character 1 - Max Wisdom + code:7E1052:63+7E1057:63 + cheat + description:Character 2 - Max HP + code:7E10C7:0F+7E10C8:27+7E10C9:0F+7E10CA:27 + cheat + description:Character 2 - Max MP + code:7E10CB:0F+7E10CC:27+7E10CD:0F+7E10CE:27 + cheat + description:Character 2 - Max Agility + code:7E10D0:63+7E10D5:63 + cheat + description:Character 2 - Max Strength + code:7E10CF:63+7E10D4:63 + cheat + description:Character 2 - Max Vitality + code:7E10D1:63+7E10D6:63 + cheat + description:Character 2 - Max Will + code:7E10D3:63+7E10D8:63 + cheat + description:Character 2 - Max Wisdom + code:7E10D2:63+7E10D7:63 + cheat + description:Character 3 - Max HP + code:7E1007:0F+7E1008:27+7E1009:0F+7E100A:27 + cheat + description:Character 3 - Max MP + code:7E100B:0F+7E100C:27+7E100D:0F+7E100E:27 + cheat + description:Character 3 - Max Agility + code:7E1010:63+7E1015:63 + cheat + description:Character 3 - Max Strength + code:7E100F:63+7E1014:63 + cheat + description:Character 3 - Max Vitality + code:7E1011:63+7E1016:63 + cheat + description:Character 3 - Max Will + code:7E1013:63+7E1018:63 + cheat + description:Character 3 - Max Wisdom + code:7E1012:63+7E1017:63 + cheat + description:Character 4 - Max HP + code:7E1107:0F+7E1108:27+7E1109:0F+7E110A:27 + cheat + description:Character 4 - Max MP + code:7E110B:0F+7E110C:27+7E110D:0F+7E110E:27 + cheat + description:Character 4 - Max Agility + code:7E1110:63+7E1115:63 + cheat + description:Character 4 - Max Strength + code:7E110F:63+7E1114:63 + cheat + description:Character 4 - Max Vitality + code:7E1111:63+7E1116:63 + cheat + description:Character 4 - Max Will + code:7E1113:63+7E1118:63 + cheat + description:Character 4 - Max Wisdom + code:7E1112:63+7E1117:63 + cheat + description:Character 5 - Max HP + code:7E1087:0F+7E1088:27+7E1089:0F+7E108A:27 + cheat + description:Character 5 - Max MP + code:7E108B:0F+7E108C:27+7E108D:0F+7E108E:27 + cheat + description:Character 5 - Max Agility + code:7E1090:63+7E1095:63 + cheat + description:Character 5 - Max Strength + code:7E108F:63+7E1094:63 + cheat + description:Character 5 - Max Vitality + code:7E1091:63+7E1096:63 + cheat + description:Character 5 - Max Will + code:7E1093:63+7E1098:63 + cheat + description:Character 5 - Max Wisdom + code:7E1092:63+7E1097:63 + cheat + description:Have 99 of slot 1 + code:7E1441:63 + cheat + description:Have 99 of slot 2 + code:7E1443:63 + cheat + description:Have 99 of slot 3 + code:7E1445:63 + cheat + description:Have 99 of slot 4 + code:7E1447:63 + cheat + description:Have 99 of slot 5 + code:7E1449:63 + cheat + description:Have 99 of slot 6 + code:7E144B:63 + cheat + description:Have 99 of slot 7 + code:7E144D:63 + cheat + description:Have 99 of slot 8 + code:7E144F:63 + cheat + description:Have 99 of slot 9 + code:7E1451:63 + cheat + description:Have 99 of slot 10 + code:7E1453:63 + cheat + description:Have Cure3 in slot 1 + code:7E1440:D0 + cheat + description:Have Cure3 in slot 2 + code:7E1442:D0 + cheat + description:Have Ether2 in slot 3 + code:7E1444:D2 + cheat + description:Have Elixer in slot 4 + code:7E1446:D3 + cheat + description:Have Life in slot 5 + code:7E1448:D4 + cheat + description:Have Cabin in slot 6 + code:7E144A:E3 + cheat + description:Have Spoon in slot 7 + code:7E144C:3E + cheat + description:Have Adamant Armor in slot 8 + code:7E144E:9A + +cartridge sha256:680535dc1c4196c53b40dc9c2c9bc159a77802ab8d4b474bef5dc0281c15ad06 + title:Final Fantasy II (USA) + cheat + description:Almost infinite HP (can make big and sometimes normal monsters invincible, disable to defeat them) + code:82A3-6F63 + cheat + description:Infinite MP during battles, doesn't work on twin attacks + code:8267-0D62 + cheat + description:Infinite items outside of battle except for the Whistle + code:C3CE-6F09 + cheat + description:Infinite Whistles + code:C3C4-A4D0 + cheat + description:Money doesn't decrease if you run away from a battle + code:C262-DF03+C262-D763 + cheat + description:Money doesn't decrease in shops + code:C2AD-AD69+C3AD-AFA9 + cheat + description:No random battles + code:DDD6-B28B + cheat + description:No random battles (alt) + code:1D60-0704 + cheat + description:Always fight the rarest enemy in that area + code:DA6E-6FD4 + cheat + description:Always get a treasure from each enemy defeated + code:6D32-D7DE + cheat + description:When treasures are awarded after battle, receive 5 instead of 1 + code:D926-D4D9 + cheat + description:When arrows are awarded after battle, receive 50 instead of 10 + code:7425-D769 + cheat + description:When treasures are awarded after battle, receive the rarest + code:D734-0DDE + cheat + description:Sumon the Big Chocobo anywhere by using a Carrot instead of the Whistle + code:38C4-AF00 + cheat + description:The quantity of items don't decrease when selling them + code:82A9-6FD1 + cheat + description:No music while traveling or in a town + code:1D67-A7A4 + cheat + description:Gunslinger code + code:00CE-6D69 + cheat + description:Save anywhere + code:CBBA-07A4 + cheat + description:Get at least 150 GP after each battle + code:1B39-070E+B139-076E+3C39-07AE + cheat + description:Get at least 255 GP after each battle + code:1B39-070E+EE39-076E+3C39-07AE + cheat + description:Get at least 65,536 GP after each battle + code:3335-0D6E + cheat + description:Get 99 of items that you are given or find in a pot, treasure chest, ect + code:17BF-D404 + cheat + description:Get 99 arrows when you find them in a pot or treasure chest + code:17B4-D4D4 + cheat + description:Cure2 is ultra strong + code:A6B7-A4E2 + cheat + description:Cure2 restores HP to all members in the party during battle + code:0DB7-A482 + cheat + description:Cure2 restores all HP/MP during battle + code:F1B7-A752 + cheat + description:Fire1 spell is ultra strong + code:A6B0-D7E3 + cheat + description:Fire1 spell hits every enemy + code:AFB0-D783 + cheat + description:Ice1 spell is ultra strong + code:A6B1-DD53 + cheat + description:Ice1 spell hits every enemy + code:AFB1-DD73 + cheat + description:Lit1 spell is ultra strong + code:A6B5-DDE3 + cheat + description:Lit1 spell hits every enemy + code:AFB5-DD83 + cheat + description:Infinite HP + code:03CAE6:BD + cheat + description:Automatically win battles (no EXP or gold gained) + code:7E1801:02+7E1800:08 + cheat + description:65,000+ exp points after each battle + code:7E3592:FF+7E359E:FF + cheat + description:Character 1 - Max HP + code:7E1047:0F+7E1048:27+7E1049:0F+7E104A:27 + cheat + description:Character 1 - Max MP + code:7E104B:0F+7E104C:27+7E104D:0F+7E104E:27 + cheat + description:Character 1 - Max Agility + code:7E1050:63+7E1055:63 + cheat + description:Character 1 - Max Strength + code:7E104F:63+7E1054:63 + cheat + description:Character 1 - Max Vitality + code:7E1051:63+7E1056:63 + cheat + description:Character 1 - Max Will + code:7E1053:63+7E1058:63 + cheat + description:Character 1 - Max Wisdom + code:7E1052:63+7E1057:63 + cheat + description:Character 2 - Max HP + code:7E10C7:0F+7E10C8:27+7E10C9:0F+7E10CA:27 + cheat + description:Character 2 - Max MP + code:7E10CB:0F+7E10CC:27+7E10CD:0F+7E10CE:27 + cheat + description:Character 2 - Max Agility + code:7E10D0:63+7E10D5:63 + cheat + description:Character 2 - Max Strength + code:7E10CF:63+7E10D4:63 + cheat + description:Character 2 - Max Vitality + code:7E10D1:63+7E10D6:63 + cheat + description:Character 2 - Max Will + code:7E10D3:63+7E10D8:63 + cheat + description:Character 2 - Max Wisdom + code:7E10D2:63+7E10D7:63 + cheat + description:Character 3 - Max HP + code:7E1007:0F+7E1008:27+7E1009:0F+7E100A:27 + cheat + description:Character 3 - Max MP + code:7E100B:0F+7E100C:27+7E100D:0F+7E100E:27 + cheat + description:Character 3 - Max Agility + code:7E1010:63+7E1015:63 + cheat + description:Character 3 - Max Strength + code:7E100F:63+7E1014:63 + cheat + description:Character 3 - Max Vitality + code:7E1011:63+7E1016:63 + cheat + description:Character 3 - Max Will + code:7E1013:63+7E1018:63 + cheat + description:Character 3 - Max Wisdom + code:7E1012:63+7E1017:63 + cheat + description:Character 4 - Max HP + code:7E1107:0F+7E1108:27+7E1109:0F+7E110A:27 + cheat + description:Character 4 - Max MP + code:7E110B:0F+7E110C:27+7E110D:0F+7E110E:27 + cheat + description:Character 4 - Max Agility + code:7E1110:63+7E1115:63 + cheat + description:Character 4 - Max Strength + code:7E110F:63+7E1114:63 + cheat + description:Character 4 - Max Vitality + code:7E1111:63+7E1116:63 + cheat + description:Character 4 - Max Will + code:7E1113:63+7E1118:63 + cheat + description:Character 4 - Max Wisdom + code:7E1112:63+7E1117:63 + cheat + description:Character 5 - Max HP + code:7E1087:0F+7E1088:27+7E1089:0F+7E108A:27 + cheat + description:Character 5 - Max MP + code:7E108B:0F+7E108C:27+7E108D:0F+7E108E:27 + cheat + description:Character 5 - Max Agility + code:7E1090:63+7E1095:63 + cheat + description:Character 5 - Max Strength + code:7E108F:63+7E1094:63 + cheat + description:Character 5 - Max Vitality + code:7E1091:63+7E1096:63 + cheat + description:Character 5 - Max Will + code:7E1093:63+7E1098:63 + cheat + description:Character 5 - Max Wisdom + code:7E1092:63+7E1097:63 + cheat + description:Have 99 of slot 1 + code:7E1441:63 + cheat + description:Have 99 of slot 2 + code:7E1443:63 + cheat + description:Have 99 of slot 3 + code:7E1445:63 + cheat + description:Have 99 of slot 4 + code:7E1447:63 + cheat + description:Have 99 of slot 5 + code:7E1449:63 + cheat + description:Have 99 of slot 6 + code:7E144B:63 + cheat + description:Have 99 of slot 7 + code:7E144D:63 + cheat + description:Have 99 of slot 8 + code:7E144F:63 + cheat + description:Have 99 of slot 9 + code:7E1451:63 + cheat + description:Have 99 of slot 10 + code:7E1453:63 + cheat + description:Have Cure3 in slot 1 + code:7E1440:D0 + cheat + description:Have Cure3 in slot 2 + code:7E1442:D0 + cheat + description:Have Ether2 in slot 3 + code:7E1444:D2 + cheat + description:Have Elixer in slot 4 + code:7E1446:D3 + cheat + description:Have Life in slot 5 + code:7E1448:D4 + cheat + description:Have Cabin in slot 6 + code:7E144A:E3 + cheat + description:Have Spoon in slot 7 + code:7E144C:3E + cheat + description:Have Adamant Armor in slot 8 + code:7E144E:9A + +cartridge sha256:10eccc5d2fab81346dd759f6be478dcb682eef981e8d3d662da176e1f9a996bc + title:Final Fantasy III (USA) (Rev 1) + cheat + description:Party has almost max HP and MP + code:EEDB-EDA8 + cheat + description:Activate Terra's Morph command + code:DAF2-9A58 + cheat + description:Infinite Morph time out of battle + code:EEFE-F288 + cheat + description:Infinite Morph time in battle + code:EE77-2A58 + cheat + description:All items in shops are free (disable to sell items) + code:108C-EF03+108C-E4A3 + cheat + description:Infinite item use + code:3CB8-5DAE + cheat + description:Infinite item use (alt) + code:3CBC-576E + cheat + description:Protect from all status ailments + code:3513-5147+E613-5117 + cheat + description:Learn all spells after one battle + code:8D17-54A6 + cheat + description:Earn 65,000+ exp points after each battle + code:0793-54D8 + cheat + description:Earn tons of EXP after a battle (level 99 takes two battles) + code:0493-54D8 + cheat + description:Auto cast Float, Regen, Haste, Shell, Safe and Rflect + code:3813-51C7 + cheat + description:Remove curse from Cursed Shield after only 1 battle + code:DD1D-7D66 + cheat + description:Steal command always gets the more rare item an enemy has + code:DD72-57AC + cheat + description:Mog never stumbles when he dances + code:DDFC-ED0B + cheat + description:Party has Sprint Shoes and Moogle Charm effect + code:AADC-EF08 + cheat + description:Party has Sprint Shoes and Moogle Charm effect (alt) + code:AADC-EDA8 + cheat + description:Party has Offering effect + code:FC47-570C+3C47-576C + cheat + description:Party has Merit Award effect + code:DDB9-746E + cheat + description:Party has Economizer effect + code:DD97-5FDA+DD90-EFDB + cheat + description:Offering gives character instant kill attacks + code:7EF4-8F0B + cheat + description:Enable all characters (once you are able to switch) + code:EEF2-BE88+EEF2-BEE8 + cheat + description:Have 94 of all items when arrange is used + code:CB48-8462+6C48-87D2+CE44-E7A2+2347-ED62 + cheat + description:Have all Blitz's + code:EEF4-9378 + cheat + description:Have all Dance's + code:EEF0-9E78 + cheat + description:Have all Lore's + code:EEF4-9358+EEF4-9388+EEF4-93E8 + cheat + description:Have all SwdTech's + code:EEFE-F2E8 + cheat + description:Have all Espers + code:EEF1-B35C+EEF1-B38C+EEF1-B3EC+EEF1-BE7C + cheat + description:Enemy 1 has 0 HP + code:DD7E-2E7C+DD7E-2E5C + cheat + description:Enemy 2 has 0 HP + code:DD7E-2E8C+DD7E-2EEC + cheat + description:Enemy 3 has 0 HP + code:DD7D-FA78+DD7D-FA58 + cheat + description:Enemy 4 has 0 HP + code:DD7D-FA88+DD7D-FAE8 + cheat + description:Enemy 5 has 0 HP + code:DD7D-F278+DD7D-F258 + cheat + description:Enemy 6 has 0 HP + code:DD7D-F288+DD7D-F2E8 + cheat + description:Faster up/down movement on world map + code:4DFB-EB88+3DF3-E6E8 + cheat + description:Faster left/right movement on world map + code:4DFE-8C88+3DF0-EC78 + cheat + description:Save anywhere + code:6DDD-BA56 + cheat + description:Start Terra with Man-eater equipped + code:D15C-78E5 + cheat + description:Start Terra with Excalibur equipped + code:F65C-78E5 + cheat + description:Start Terra with Illumina equipped + code:FC5C-78E5 + cheat + description:Start Terra with Atma equipped + code:FA5C-78E5 + cheat + description:Start Terra with Tempest equipped + code:435C-78E5 + cheat + description:Start Terra with Blizzard equipped + code:D35C-78E5 + cheat + description:Start Terra with Enhancer equipped + code:F75C-78E5 + cheat + description:Start Terra with Mithril shield equipped + code:9A58-7675 + cheat + description:Start Terra with Gold shield equipped + code:9258-7675 + cheat + description:Start Terra with Ice shield equipped + code:1F58-7675 + cheat + description:Start Terra with Fire shield equipped + code:1D58-7675 + cheat + description:Start Terra with Hairband equipped + code:1C58-7655 + cheat + description:Start Terra with Leather hat equipped + code:1B58-7655 + cheat + description:Start Terra with Circlet equipped + code:5C58-7655 + cheat + description:Start Terra with Mystery veil equipped + code:5B58-7655 + cheat + description:Start Terra with Red cap equipped + code:5658-7655 + cheat + description:Start Terra with Silk robe equipped + code:6658-7685 + cheat + description:Start Terra with Mithril vest equipped + code:6B58-7685 + cheat + description:Start Terra with White dress equipped + code:6858-7685 + cheat + description:Start Terra with Genji armor equipped + code:BC58-7685 + cheat + description:Start Terra with Force armor equipped + code:B058-7685 + cheat + description:Party has Sprint Shoes and Moogle Charm effect (alt 2) + code:7E11DF:22 + cheat + description:Have 99 Sprint Shoes in slot 10 + code:7E1872:E6+7E1972:63 + cheat + description:Enemy 1 has 0 HP (alt) + code:7E3BFC:00+7E3BFD:00 + cheat + description:Enemy 2 has 0 HP (alt) + code:7E3BFE:00+7E3BFF:00 + cheat + description:Enemy 3 has 0 HP (alt) + code:7E3C00:00+7E3C01:00 + cheat + description:Enemy 4 has 0 HP (alt) + code:7E3C02:00+7E3C03:00 + cheat + description:Enemy 5 has 0 HP (alt) + code:7E3C04:00+7E3C05:00 + cheat + description:Enemy 6 has 0 HP (alt) + code:7E3C06:00+7E3C07:00 + cheat + description:Save anywhere (alt) + code:7E0201:80 + cheat + description:Have all Rage's + code:7E1D49:FF+7E1D42:FF+7E1D3B:FF+7E1D3E:FF+7E1D4A:FF+7E1D46:FF+7E1D43:FF+7E1D47:FF+7E1D3C:FF+7E1D32:FF+7E1D48:FF+7E1D4B:FF+7E1D33:FF+7E1D2C:FF+7E1D44:FF+7E1D34:FF+7E1D2D:FF+7E1D3D:FF+7E1D2E:FF+7E1D45:FF+7E1D2F:FF+7E1D30:FF+7E1D31:FF+7E1D35:FF+7E1D36:FF+7E1D37:FF+7E1D3F:FF+7E1D38:FF+7E1D40:FF+7E1D39:FF+7E1D41:FF+7E1D3A:FF + cheat + description:Celes - Level 99 + code:7E16E6:63 + cheat + description:Celes - 9999 HP + code:7E16E7:0F+7E16E8:27 + cheat + description:Celes - 9999 Max HP + code:7E16E9:0F+7E16EA:27 + cheat + description:Celes - 9999 MP + code:7E16EB:0F+7E16EC:27 + cheat + description:Celes - 9999 Max MP + code:7E16ED:0F+7E16EE:27 + cheat + description:Celes - No Ailments + code:7E16F2:00 + cheat + description:Celes - Float always on + code:7E16F3:FF + cheat + description:Celes - 255 Vigor + code:7E16F8:FF + cheat + description:Celes - 255 Speed + code:7E16F9:FF + cheat + description:Celes - 255 Stamina + code:7E16FA:FF + cheat + description:Celes - 255 Magic Power + code:7E16FB:FF + cheat + description:Cyan - Level 99 + code:7E1652:63 + cheat + description:Cyan - 9999 HP + code:7E1653:0F+7E1654:27 + cheat + description:Cyan - 9999 Max HP + code:7E1655:0F+7E1656:27 + cheat + description:Cyan - 9999 MP + code:7E1657:0F+7E1658:27 + cheat + description:Cyan - 9999 Max MP + code:7E1659:0F+7E165A:27 + cheat + description:Cyan - No Ailments + code:7E165E:00 + cheat + description:Cyan - Float always on + code:7E165F:FF + cheat + description:Cyan - 255 Vigor + code:7E1664:FF + cheat + description:Cyan - 255 Speed + code:7E1665:FF + cheat + description:Cyan - 255 Stamina + code:7E1666:FF + cheat + description:Cyan - 255 Magic Power + code:7E1667:FF + cheat + description:Edgar - Level 99 + code:7E169C:63 + cheat + description:Edgar - 9999 HP + code:7E169D:0F+7E169E:27 + cheat + description:Edgar - 9999 Max HP + code:7E169F:0F+7E16A0:27 + cheat + description:Edgar - 9999 MP + code:7E16A1:0F+7E16A2:27 + cheat + description:Edgar - 9999 Max MP + code:7E16A3:0F+7E16A4:27 + cheat + description:Edgar - No Ailments + code:7E16A8:00 + cheat + description:Edgar - Float always on + code:7E16A9:FF + cheat + description:Edgar - 255 Vigor + code:7E16AE:FF + cheat + description:Edgar - 255 Speed + code:7E16AF:FF + cheat + description:Edgar - 255 Stamina + code:7E16B0:FF + cheat + description:Edgar - 255 Magic Power + code:7E16B1:FF + cheat + description:Gau - Level 99 + code:7E179F:63 + cheat + description:Gau - 9999 HP + code:7E17A0:0F+7E17A1:27 + cheat + description:Gau - 9999 Max HP + code:7E17A2:0F+7E17A3:27 + cheat + description:Gau - 9999 MP + code:7E17A4:0F+7E17A5:27 + cheat + description:Gau - 9999 Max MP + code:7E17A6:0F+7E17A7:27 + cheat + description:Gau - No Ailments + code:7E17AB:00 + cheat + description:Gau - Float always on + code:7E17AC:FF + cheat + description:Gau - 255 Vigor + code:7E17B1:FF + cheat + description:Gau - 255 Speed + code:7E17B2:FF + cheat + description:Gau - 255 Stamina + code:7E17B3:FF + cheat + description:Gau - 255 Magic Power + code:7E17B4:FF + cheat + description:Gogo - Level 99 + code:7E17C4:63 + cheat + description:Gogo - 9999 HP + code:7E17C5:0F+7E17C6:27 + cheat + description:Gogo - 9999 Max HP + code:7E17C7:0F+7E17C8:27 + cheat + description:Gogo - 9999 MP + code:7E17C9:0F+7E17CA:27 + cheat + description:Gogo - 9999 Max MP + code:7E17CB:0F+7E17CC:27 + cheat + description:Gogo - No Ailments + code:7E17D0:00 + cheat + description:Gogo - Float always on + code:7E17D1:FF + cheat + description:Gogo - 255 Vigor + code:7E17D6:FF + cheat + description:Gogo - 255 Speed + code:7E17D7:FF + cheat + description:Gogo - 255 Stamina + code:7E17D8:FF + cheat + description:Gogo - 255 Magic Power + code:7E17D9:FF + cheat + description:Locke - Level 99 + code:7E162D:63 + cheat + description:Locke - 9999 HP + code:7E162E:0F+7E162F:27 + cheat + description:Locke - 9999 Max HP + code:7E1630:0F+7E1631:27 + cheat + description:Locke - 9999 MP + code:7E1632:0F+7E1633:27 + cheat + description:Locke - 9999 Max MP + code:7E1634:0F+7E1635:27 + cheat + description:Locke - No Ailments + code:7E1639:00 + cheat + description:Locke - Float always on + code:7E163A:FF + cheat + description:Locke - 255 Vigor + code:7E163F:FF + cheat + description:Locke - 255 Speed + code:7E1640:FF + cheat + description:Locke - 255 Stamina + code:7E1641:FF + cheat + description:Locke - 255 Magic Power + code:7E1642:FF + cheat + description:Mog - Level 99 + code:7E177A:63 + cheat + description:Mog - 9999 HP + code:7E177B:0F+7E177C:27 + cheat + description:Mog - 9999 Max HP + code:7E177D:0F+7E177E:27 + cheat + description:Mog - 9999 MP + code:7E177F:0F+7E1780:27 + cheat + description:Mog - 9999 Max MP + code:7E1781:0F+7E1782:27 + cheat + description:Mog - No Ailments + code:7E1786:00 + cheat + description:Mog - Float always on + code:7E1787:FF + cheat + description:Mog - 255 Vigor + code:7E178C:FF + cheat + description:Mog - 255 Speed + code:7E178D:FF + cheat + description:Mog - 255 Stamina + code:7E178E:FF + cheat + description:Mog - 255 Magic Power + code:7E178F:FF + cheat + description:Relm - Level 99 + code:7E1730:63 + cheat + description:Relm - 9999 HP + code:7E1731:0F+7E1732:27 + cheat + description:Relm - 9999 Max HP + code:7E1733:0F+7E1734:27 + cheat + description:Relm - 9999 MP + code:7E1735:0F+7E1736:27 + cheat + description:Relm - 9999 Max MP + code:7E1737:0F+7E1738:27 + cheat + description:Relm - No Ailments + code:7E173C:00 + cheat + description:Relm - Float always on + code:7E173D:FF + cheat + description:Relm - 255 Vigor + code:7E1742:FF + cheat + description:Relm - 255 Speed + code:7E1743:FF + cheat + description:Relm - 255 Stamina + code:7E1744:FF + cheat + description:Relm - 255 Magic Power + code:7E1745:FF + cheat + description:Sabin - Level 99 + code:7E16C1:63 + cheat + description:Sabin - 9999 HP + code:7E16C2:0F+7E16C3:27 + cheat + description:Sabin - 9999 Max HP + code:7E16C4:0F+7E16C5:27 + cheat + description:Sabin - 9999 MP + code:7E16C6:0F+7E16C7:27 + cheat + description:Sabin - 9999 Max MP + code:7E16C8:0F+7E16C9:27 + cheat + description:Sabin - No Ailments + code:7E16CD:00 + cheat + description:Sabin - Float always on + code:7E16CE:FF + cheat + description:Sabin - 255 Vigor + code:7E16D3:FF + cheat + description:Sabin - 255 Speed + code:7E16D4:FF + cheat + description:Sabin - 255 Stamina + code:7E16D5:FF + cheat + description:Sabin - 255 Magic Power + code:7E16D6:FF + cheat + description:Setzer - Level 99 + code:7E1755:63 + cheat + description:Setzer - 9999 HP + code:7E1756:0F+7E1757:27 + cheat + description:Setzer - 9999 Max HP + code:7E1758:0F+7E1759:27 + cheat + description:Setzer - 9999 MP + code:7E175A:0F+7E175B:27 + cheat + description:Setzer - 9999 Max MP + code:7E175C:0F+7E175D:27 + cheat + description:Setzer - No Ailments + code:7E1761:00 + cheat + description:Setzer - Float always on + code:7E1762:FF + cheat + description:Setzer - 255 Vigor + code:7E1767:FF + cheat + description:Setzer - 255 Speed + code:7E1768:FF + cheat + description:Setzer - 255 Stamina + code:7E1769:FF + cheat + description:Setzer - 255 Magic Power + code:7E176A:FF + cheat + description:Shadow - Level 99 + code:7E1677:63 + cheat + description:Shadow - 9999 HP + code:7E1678:0F+7E1679:27 + cheat + description:Shadow - 9999 Max HP + code:7E167A:0F+7E167B:27 + cheat + description:Shadow - 9999 MP + code:7E167C:0F+7E167D:27 + cheat + description:Shadow - 9999 Max MP + code:7E167E:0F+7E167F:27 + cheat + description:Shadow - No Ailments + code:7E1683:00 + cheat + description:Shadow - Float always on + code:7E1684:FF + cheat + description:Shadow - 255 Vigor + code:7E1689:FF + cheat + description:Shadow - 255 Speed + code:7E168A:FF + cheat + description:Shadow - 255 Stamina + code:7E168B:FF + cheat + description:Shadow - 255 Magic Power + code:7E168C:FF + cheat + description:Strago - Level 99 + code:7E170B:63 + cheat + description:Strago - 9999 HP + code:7E170C:0F+7E170D:27 + cheat + description:Strago - 9999 Max HP + code:7E170E:0F+7E170F:27 + cheat + description:Strago - 9999 MP + code:7E1710:0F+7E1711:27 + cheat + description:Strago - 9999 Max MP + code:7E1712:0F+7E1713:27 + cheat + description:Strago - No Ailments + code:7E1717:00 + cheat + description:Strago - Float always on + code:7E1718:FF + cheat + description:Strago - 255 Vigor + code:7E171D:FF + cheat + description:Strago - 255 Speed + code:7E171E:FF + cheat + description:Strago - 255 Stamina + code:7E171F:FF + cheat + description:Strago - 255 Magic Power + code:7E1720:FF + cheat + description:Terra - Level 99 + code:7E1608:63 + cheat + description:Terra - 9999 HP + code:7E1609:0F+7E160A:27 + cheat + description:Terra - 9999 Max HP + code:7E160B:0F+7E160C:27 + cheat + description:Terra - 9999 MP + code:7E160D:0F+7E160E:27 + cheat + description:Terra - 9999 Max MP + code:7E160F:0F+7E1610:27 + cheat + description:Terra - No ailments + code:7E1614:00 + cheat + description:Terra - Float always on + code:7E1615:FF + cheat + description:Terra - 255 Vigor + code:7E161A:FF + cheat + description:Terra - 255 Speed + code:7E161B:FF + cheat + description:Terra - 255 Stamina + code:7E161C:FF + cheat + description:Terra - 255 Magic Power + code:7E161D:FF + cheat + description:Umaro - Level 99 + code:7E17E9:63 + cheat + description:Umaro - 9999 HP + code:7E17EA:0F+7E17EB:27 + cheat + description:Umaro - 9999 Max HP + code:7E17EC:0F+7E17ED:27 + cheat + description:Umaro - 9999 MP + code:7E17EE:0F+7E17EF:27 + cheat + description:Umaro - 9999 Max MP + code:7E17F0:0F+7E17F1:27 + cheat + description:Umaro - No Ailments + code:7E17F5:00 + cheat + description:Umaro - Float always on + code:7E17F6:FF + cheat + description:Umaro - 255 Vigor + code:7E17FB:FF + cheat + description:Umaro - 255 Speed + code:7E17FC:FF + cheat + description:Umaro - 255 Stamina + code:7E17FD:FF + cheat + description:Umaro - 255 Magic Power + code:7E17FE:FF + +cartridge sha256:0f51b4fca41b7fd509e4b8f9d543151f68efa5e97b08493e4b2a0c06f5d8d5e2 + title:Final Fantasy III (USA) + cheat + description:Party has almost max HP and MP + code:EEDB-EDA8 + cheat + description:Activate Terra's Morph command + code:DAF2-9A58 + cheat + description:Infinite Morph time out of battle + code:EEFE-F288 + cheat + description:Infinite Morph time in battle + code:EE77-2A58 + cheat + description:All items in shops are free (disable to sell items) + code:108C-EF03+108C-E4A3 + cheat + description:Infinite item use + code:3CB8-5DAE + cheat + description:Protect from all status ailments + code:3513-5147+E613-5117 + cheat + description:Learn all spells after one battle + code:8D17-54A6 + cheat + description:Earn 65,000+ exp points after each battle + code:0793-54D8 + cheat + description:Earn tons of EXP after a battle (level 99 takes two battles) + code:0493-54D8 + cheat + description:Auto Cast Float, Regen, Haste, Shell, Safe and Rflect + code:3813-51C7 + cheat + description:Vigor/Speed/Stamina/MagPwr becomes 255 + code:D762-EF68 + cheat + description:Remove curse from Cursed Shield after only 1 battle + code:DD1D-7D66 + cheat + description:Steal command always gets the more rare item an enemy has + code:DD72-57AC + cheat + description:Mog never stumbles when he dances + code:DDFC-ED0B + cheat + description:Party has Sprint Shoes and Moogle Charm effect + code:44F2-9EE6 + cheat + description:Party has Offering effect + code:FC47-570C+3C47-576C + cheat + description:Party has Merit Award effect + code:DDB9-746E + cheat + description:Party has Economizer effect + code:DD97-5FDA+DD90-EFDB + cheat + description:Offering gives character instant kill attacks + code:7EF4-8F0B + cheat + description:Enemy 1 has 0 HP + code:DD7E-2E7C+DD7E-2E5C + cheat + description:Enemy 2 has 0 HP + code:DD7E-2E8C+DD7E-2EEC + cheat + description:Enemy 3 has 0 HP + code:DD7D-FA78+DD7D-FA58 + cheat + description:Enemy 4 has 0 HP + code:DD7D-FA88+DD7D-FAE8 + cheat + description:Enemy 5 has 0 HP + code:DD7D-F278+DD7D-F258 + cheat + description:Enemy 6 has 0 HP + code:DD7D-F288+DD7D-F2E8 + cheat + description:Have 94 of all items when arrange is used + code:CB48-8462+6C48-87D2+CE44-E7A2+2347-ED62 + cheat + description:Have all Blitz's + code:EEF4-9378 + cheat + description:Have all Dance's + code:EEF0-9E78 + cheat + description:Have all Lore's + code:EEF4-9358+EEF4-9388+EEF4-93E8 + cheat + description:Have all SwdTech's + code:EEFE-F2E8 + cheat + description:Have all Espers + code:EEF1-B35C+EEF1-B38C+EEF1-B3EC+EEF1-BE7C + cheat + description:Faster up/down movement on world map + code:4DFB-EB88+3DF3-E6E8 + cheat + description:Faster left/right movement on world map + code:4DFE-8C88+3DF0-EC78 + cheat + description:Enable all characters (once you are able to switch) + code:EEF2-BE88+EEF2-BEE8 + cheat + description:Save anywhere + code:6DDD-BA56 + cheat + description:Start Terra with Man-eater equipped + code:D15C-78E5 + cheat + description:Start Terra with Excalibur equipped + code:F65C-78E5 + cheat + description:Start Terra with Illumina equipped + code:FC5C-78E5 + cheat + description:Start Terra with Atma equipped + code:FA5C-78E5 + cheat + description:Start Terra with Tempest equipped + code:435C-78E5 + cheat + description:Start Terra with Blizzard equipped + code:D35C-78E5 + cheat + description:Start Terra with Enhancer equipped + code:F75C-78E5 + cheat + description:Start Terra with Mithril shield equipped + code:9A58-7675 + cheat + description:Start Terra with Gold shield equipped + code:9258-7675 + cheat + description:Start Terra with Ice shield equipped + code:1F58-7675 + cheat + description:Start Terra with Fire shield equipped + code:1D58-7675 + cheat + description:Start Terra with Hairband equipped + code:1C58-7655 + cheat + description:Start Terra with Leather hat equipped + code:1B58-7655 + cheat + description:Start Terra with Circlet equipped + code:5C58-7655 + cheat + description:Start Terra with Mystery veil equipped + code:5B58-7655 + cheat + description:Start Terra with Red cap equipped + code:5658-7655 + cheat + description:Start Terra with Silk robe equipped + code:6658-7685 + cheat + description:Start Terra with Mithril vest equipped + code:6B58-7685 + cheat + description:Start Terra with White dress equipped + code:6858-7685 + cheat + description:Start Terra with Genji armor equipped + code:BC58-7685 + cheat + description:Start Terra with Force armor equipped + code:B058-7685 + cheat + description:Party has Sprint Shoes and Moogle Charm effect (alt) + code:7E11DF:22 + cheat + description:Have 99 Sprint Shoes in slot 10 + code:7E1872:E6+7E1972:63 + cheat + description:Enemy 1 has 0 HP (alt) + code:7E3BFC:00+7E3BFD:00 + cheat + description:Enemy 2 has 0 HP (alt) + code:7E3BFE:00+7E3BFF:00 + cheat + description:Enemy 3 has 0 HP (alt) + code:7E3C00:00+7E3C01:00 + cheat + description:Enemy 4 has 0 HP (alt) + code:7E3C02:00+7E3C03:00 + cheat + description:Enemy 5 has 0 HP (alt) + code:7E3C04:00+7E3C05:00 + cheat + description:Enemy 6 has 0 HP (alt) + code:7E3C06:00+7E3C07:00 + cheat + description:Have all Rage's + code:7E1D49:FF+7E1D42:FF+7E1D3B:FF+7E1D3E:FF+7E1D4A:FF+7E1D46:FF+7E1D43:FF+7E1D47:FF+7E1D3C:FF+7E1D32:FF+7E1D48:FF+7E1D4B:FF+7E1D33:FF+7E1D2C:FF+7E1D44:FF+7E1D34:FF+7E1D2D:FF+7E1D3D:FF+7E1D2E:FF+7E1D45:FF+7E1D2F:FF+7E1D30:FF+7E1D31:FF+7E1D35:FF+7E1D36:FF+7E1D37:FF+7E1D3F:FF+7E1D38:FF+7E1D40:FF+7E1D39:FF+7E1D41:FF+7E1D3A:FF + cheat + description:Celes - Level 99 + code:7E16E6:63 + cheat + description:Celes - 9999 HP + code:7E16E7:0F+7E16E8:27 + cheat + description:Celes - 9999 Max HP + code:7E16E9:0F+7E16EA:27 + cheat + description:Celes - 9999 MP + code:7E16EB:0F+7E16EC:27 + cheat + description:Celes - 9999 Max MP + code:7E16ED:0F+7E16EE:27 + cheat + description:Celes - No Ailments + code:7E16F2:00 + cheat + description:Celes - Float always on + code:7E16F3:FF + cheat + description:Celes - 255 Vigor + code:7E16F8:FF + cheat + description:Celes - 255 Speed + code:7E16F9:FF + cheat + description:Celes - 255 Stamina + code:7E16FA:FF + cheat + description:Celes - 255 Magic Power + code:7E16FB:FF + cheat + description:Cyan - Level 99 + code:7E1652:63 + cheat + description:Cyan - 9999 HP + code:7E1653:0F+7E1654:27 + cheat + description:Cyan - 9999 Max HP + code:7E1655:0F+7E1656:27 + cheat + description:Cyan - 9999 MP + code:7E1657:0F+7E1658:27 + cheat + description:Cyan - 9999 Max MP + code:7E1659:0F+7E165A:27 + cheat + description:Cyan - No Ailments + code:7E165E:00 + cheat + description:Cyan - Float always on + code:7E165F:FF + cheat + description:Cyan - 255 Vigor + code:7E1664:FF + cheat + description:Cyan - 255 Speed + code:7E1665:FF + cheat + description:Cyan - 255 Stamina + code:7E1666:FF + cheat + description:Cyan - 255 Magic Power + code:7E1667:FF + cheat + description:Edgar - Level 99 + code:7E169C:63 + cheat + description:Edgar - 9999 HP + code:7E169D:0F+7E169E:27 + cheat + description:Edgar - 9999 Max HP + code:7E169F:0F+7E16A0:27 + cheat + description:Edgar - 9999 MP + code:7E16A1:0F+7E16A2:27 + cheat + description:Edgar - 9999 Max MP + code:7E16A3:0F+7E16A4:27 + cheat + description:Edgar - No Ailments + code:7E16A8:00 + cheat + description:Edgar - Float always on + code:7E16A9:FF + cheat + description:Edgar - 255 Vigor + code:7E16AE:FF + cheat + description:Edgar - 255 Speed + code:7E16AF:FF + cheat + description:Edgar - 255 Stamina + code:7E16B0:FF + cheat + description:Edgar - 255 Magic Power + code:7E16B1:FF + cheat + description:Gau - Level 99 + code:7E179F:63 + cheat + description:Gau - 9999 HP + code:7E17A0:0F+7E17A1:27 + cheat + description:Gau - 9999 Max HP + code:7E17A2:0F+7E17A3:27 + cheat + description:Gau - 9999 MP + code:7E17A4:0F+7E17A5:27 + cheat + description:Gau - 9999 Max MP + code:7E17A6:0F+7E17A7:27 + cheat + description:Gau - No Ailments + code:7E17AB:00 + cheat + description:Gau - Float always on + code:7E17AC:FF + cheat + description:Gau - 255 Vigor + code:7E17B1:FF + cheat + description:Gau - 255 Speed + code:7E17B2:FF + cheat + description:Gau - 255 Stamina + code:7E17B3:FF + cheat + description:Gau - 255 Magic Power + code:7E17B4:FF + cheat + description:Gogo - Level 99 + code:7E17C4:63 + cheat + description:Gogo - 9999 HP + code:7E17C5:0F+7E17C6:27 + cheat + description:Gogo - 9999 Max HP + code:7E17C7:0F+7E17C8:27 + cheat + description:Gogo - 9999 MP + code:7E17C9:0F+7E17CA:27 + cheat + description:Gogo - 9999 Max MP + code:7E17CB:0F+7E17CC:27 + cheat + description:Gogo - No Ailments + code:7E17D0:00 + cheat + description:Gogo - Float always on + code:7E17D1:FF + cheat + description:Gogo - 255 Vigor + code:7E17D6:FF + cheat + description:Gogo - 255 Speed + code:7E17D7:FF + cheat + description:Gogo - 255 Stamina + code:7E17D8:FF + cheat + description:Gogo - 255 Magic Power + code:7E17D9:FF + cheat + description:Locke - Level 99 + code:7E162D:63 + cheat + description:Locke - 9999 HP + code:7E162E:0F+7E162F:27 + cheat + description:Locke - 9999 Max HP + code:7E1630:0F+7E1631:27 + cheat + description:Locke - 9999 MP + code:7E1632:0F+7E1633:27 + cheat + description:Locke - 9999 Max MP + code:7E1634:0F+7E1635:27 + cheat + description:Locke - No Ailments + code:7E1639:00 + cheat + description:Locke - Float always on + code:7E163A:FF + cheat + description:Locke - 255 Vigor + code:7E163F:FF + cheat + description:Locke - 255 Speed + code:7E1640:FF + cheat + description:Locke - 255 Stamina + code:7E1641:FF + cheat + description:Locke - 255 Magic Power + code:7E1642:FF + cheat + description:Mog - Level 99 + code:7E177A:63 + cheat + description:Mog - 9999 HP + code:7E177B:0F+7E177C:27 + cheat + description:Mog - 9999 Max HP + code:7E177D:0F+7E177E:27 + cheat + description:Mog - 9999 MP + code:7E177F:0F+7E1780:27 + cheat + description:Mog - 9999 Max MP + code:7E1781:0F+7E1782:27 + cheat + description:Mog - No Ailments + code:7E1786:00 + cheat + description:Mog - Float always on + code:7E1787:FF + cheat + description:Mog - 255 Vigor + code:7E178C:FF + cheat + description:Mog - 255 Speed + code:7E178D:FF + cheat + description:Mog - 255 Stamina + code:7E178E:FF + cheat + description:Mog - 255 Magic Power + code:7E178F:FF + cheat + description:Relm - Level 99 + code:7E1730:63 + cheat + description:Relm - 9999 HP + code:7E1731:0F+7E1732:27 + cheat + description:Relm - 9999 Max HP + code:7E1733:0F+7E1734:27 + cheat + description:Relm - 9999 MP + code:7E1735:0F+7E1736:27 + cheat + description:Relm - 9999 Max MP + code:7E1737:0F+7E1738:27 + cheat + description:Relm - No Ailments + code:7E173C:00 + cheat + description:Relm - Float always on + code:7E173D:FF + cheat + description:Relm - 255 Vigor + code:7E1742:FF + cheat + description:Relm - 255 Speed + code:7E1743:FF + cheat + description:Relm - 255 Stamina + code:7E1744:FF + cheat + description:Relm - 255 Magic Power + code:7E1745:FF + cheat + description:Sabin - Level 99 + code:7E16C1:63 + cheat + description:Sabin - 9999 HP + code:7E16C2:0F+7E16C3:27 + cheat + description:Sabin - 9999 Max HP + code:7E16C4:0F+7E16C5:27 + cheat + description:Sabin - 9999 MP + code:7E16C6:0F+7E16C7:27 + cheat + description:Sabin - 9999 Max MP + code:7E16C8:0F+7E16C9:27 + cheat + description:Sabin - No Ailments + code:7E16CD:00 + cheat + description:Sabin - Float always on + code:7E16CE:FF + cheat + description:Sabin - 255 Vigor + code:7E16D3:FF + cheat + description:Sabin - 255 Speed + code:7E16D4:FF + cheat + description:Sabin - 255 Stamina + code:7E16D5:FF + cheat + description:Sabin - 255 Magic Power + code:7E16D6:FF + cheat + description:Setzer - Level 99 + code:7E1755:63 + cheat + description:Setzer - 9999 HP + code:7E1756:0F+7E1757:27 + cheat + description:Setzer - 9999 Max HP + code:7E1758:0F+7E1759:27 + cheat + description:Setzer - 9999 MP + code:7E175A:0F+7E175B:27 + cheat + description:Setzer - 9999 Max MP + code:7E175C:0F+7E175D:27 + cheat + description:Setzer - No Ailments + code:7E1761:00 + cheat + description:Setzer - Float always on + code:7E1762:FF + cheat + description:Setzer - 255 Vigor + code:7E1767:FF + cheat + description:Setzer - 255 Speed + code:7E1768:FF + cheat + description:Setzer - 255 Stamina + code:7E1769:FF + cheat + description:Setzer - 255 Magic Power + code:7E176A:FF + cheat + description:Shadow - Level 99 + code:7E1677:63 + cheat + description:Shadow - 9999 HP + code:7E1678:0F+7E1679:27 + cheat + description:Shadow - 9999 Max HP + code:7E167A:0F+7E167B:27 + cheat + description:Shadow - 9999 MP + code:7E167C:0F+7E167D:27 + cheat + description:Shadow - 9999 Max MP + code:7E167E:0F+7E167F:27 + cheat + description:Shadow - No Ailments + code:7E1683:00 + cheat + description:Shadow - Float always on + code:7E1684:FF + cheat + description:Shadow - 255 Vigor + code:7E1689:FF + cheat + description:Shadow - 255 Speed + code:7E168A:FF + cheat + description:Shadow - 255 Stamina + code:7E168B:FF + cheat + description:Shadow - 255 Magic Power + code:7E168C:FF + cheat + description:Strago - Level 99 + code:7E170B:63 + cheat + description:Strago - 9999 HP + code:7E170C:0F+7E170D:27 + cheat + description:Strago - 9999 Max HP + code:7E170E:0F+7E170F:27 + cheat + description:Strago - 9999 MP + code:7E1710:0F+7E1711:27 + cheat + description:Strago - 9999 Max MP + code:7E1712:0F+7E1713:27 + cheat + description:Strago - No Ailments + code:7E1717:00 + cheat + description:Strago - Float always on + code:7E1718:FF + cheat + description:Strago - 255 Vigor + code:7E171D:FF + cheat + description:Strago - 255 Speed + code:7E171E:FF + cheat + description:Strago - 255 Stamina + code:7E171F:FF + cheat + description:Strago - 255 Magic Power + code:7E1720:FF + cheat + description:Terra - Level 99 + code:7E1608:63 + cheat + description:Terra - 9999 HP + code:7E1609:0F+7E160A:27 + cheat + description:Terra - 9999 Max HP + code:7E160B:0F+7E160C:27 + cheat + description:Terra - 9999 MP + code:7E160D:0F+7E160E:27 + cheat + description:Terra - 9999 Max MP + code:7E160F:0F+7E1610:27 + cheat + description:Terra - No ailments + code:7E1614:00 + cheat + description:Terra - Float always on + code:7E1615:FF + cheat + description:Terra - 255 Vigor + code:7E161A:FF + cheat + description:Terra - 255 Speed + code:7E161B:FF + cheat + description:Terra - 255 Stamina + code:7E161C:FF + cheat + description:Terra - 255 Magic Power + code:7E161D:FF + cheat + description:Umaro - Level 99 + code:7E17E9:63 + cheat + description:Umaro - 9999 HP + code:7E17EA:0F+7E17EB:27 + cheat + description:Umaro - 9999 Max HP + code:7E17EC:0F+7E17ED:27 + cheat + description:Umaro - 9999 MP + code:7E17EE:0F+7E17EF:27 + cheat + description:Umaro - 9999 Max MP + code:7E17F0:0F+7E17F1:27 + cheat + description:Umaro - No Ailments + code:7E17F5:00 + cheat + description:Umaro - Float always on + code:7E17F6:FF + cheat + description:Umaro - 255 Vigor + code:7E17FB:FF + cheat + description:Umaro - 255 Speed + code:7E17FC:FF + cheat + description:Umaro - 255 Stamina + code:7E17FD:FF + cheat + description:Umaro - 255 Magic Power + code:7E17FE:FF + +cartridge sha256:60cca2592d0756b8c4c7a0a254fafa5ac47aa752521fd1f77dcbf4b6ee1bee90 + title:Final Fight (USA) + cheat + description:Invincibility + code:2DCD-AF6B + cheat + description:Infinite health + code:89A1-0DA1+C9C4-AD6C + cheat + description:Infinite health (alt) + code:9DDF-9278 + cheat + description:Infinite lives + code:A9C3-6F66+D433-0D6F + cheat + description:Infinite lives (alt) + code:CE33-076F + cheat + description:Infinite time + code:A2C0-A7D0 + cheat + description:Hit anywhere + code:3CA4-0FD0+40AD-04A0+7DA4-0F00+89A4-0D60+F9A4-0DA0 + cheat + description:Slower timer + code:D4C9-AFD0 + cheat + description:Faster timer + code:DDC9-AFD0 + cheat + description:Any food restores all health + code:DD8D-6F06 + cheat + description:Attack speed greatly increased + code:DFDF-9E88 + cheat + description:Start with 2 credits + code:DFC8-D4A1 + cheat + description:Start with 6 credits + code:D9C8-D4A1 + cheat + description:Start with 10 credits + code:DBC8-D4A1 + cheat + description:Start on stage 2 - Subway + code:DFEE-2E88 + cheat + description:Start on stage 3 - West Side + code:D4EE-2E88 + cheat + description:Start on stage 4 - Bay Area + code:D0EE-2E88 + cheat + description:Start on stage 5 - Uptown + code:D9EE-2E88 + cheat + description:Start on bonus stage - Car + code:D1EE-2E88 + cheat + description:Start on bonus stage - Glass + code:D5EE-2E88 + cheat + description:Enemies never get knocked down, attack until they die + code:7E0D70:00 + cheat + description:Enemy 1 has no health + code:7E1014:00 + cheat + description:Enemy 2 has no health + code:7E10B4:00 + cheat + description:Enemy 3 has no health + code:7E1154:00 + cheat + description:Bosses have no health + code:7E11F4:00+7E11F5:00 + cheat + description:Always get Knife + code:7E1C11:00 + cheat + description:Always get Sword + code:7E1C11:02 + cheat + description:Always get Pipe + code:7E1C11:04 + +cartridge sha256:744d1a16c3f99970283597ae8f43b7c3621c5f995c4566ef24b8d70b0692007b + title:Final Fight 2 (USA) + cheat + description:Invincibility + code:2D65-3706 + cheat + description:Infinite health + code:C9E1-446F+C9C8-CFDB + cheat + description:Infinite lives + code:C9CE-1DAB + cheat + description:Infinite lives (alt) + code:DDCE-1D6B + cheat + description:Infinite time + code:C2A0-1F0C + cheat + description:Infinite time (alt) + code:DDA0-1DDC + cheat + description:One hit kills + code:CBE8-47AF+EEEA-4DDF + cheat + description:Hit anywhere - both players + code:4062-1DA6+4062-14D6+406C-1DA6 + cheat + description:Faster timer + code:D4A0-1DDC + cheat + description:Barbecue restores vitality 50% instead of 95% + code:0DED-1DAC + cheat + description:Barbecue worth nothing + code:DDED-1DAC + cheat + description:Soft drink restores vitality 95% + code:6DEE-470C + cheat + description:Soft drink worth nothing + code:DDEE-470C + cheat + description:Both players can select same character + code:33C5-1404 + cheat + description:P1 and P2 can't harm each other in a 2P game + code:DDB4-4708 + cheat + description:Slow motion (disable until play begins) + code:D46A-14AF + cheat + description:Hitting someone with your super move makes you invincible + code:DFCC-C4DB + cheat + description:Hitting someone with your super move uses all your health + code:0DCC-C4DB + cheat + description:Start with 1 life + code:DDCF-C7D6 + cheat + description:Start with 3 lives + code:D4CF-C7D6 + cheat + description:Start with 7 lives + code:D1CF-C7D6 + cheat + description:Start with 10 lives + code:DBCF-C7D6 + +cartridge sha256:f9dac709b2c2859f828103a0dd980716817e2bde3b9d7e2fdea36e9bb9bed7f2 + title:Final Fight 3 (USA) + cheat + description:Infinite time + code:C2F9-84DF + cheat + description:Instant super energy + code:CBB5-5D07+46B5-5D67+DDB5-5DA7+4BB5-5F07 + cheat + description:Infinite lives + code:3C6C-84AF + cheat + description:Hit anywhere - both players + code:3DA7-E76D+D5A0-EDDD+DDA7-E7AD + cheat + description:Invincibility (blinking) - P1 + code:7E0520:02 + cheat + description:Invincibility (blinking) - P2 + code:7E0620:02 + cheat + description:Infinite health - P1 + code:7E0558:47 + cheat + description:Infinite health - P2 + code:7E0658:47 + cheat + description:Infinite lives - P1 + code:7E0515:05 + cheat + description:Infinite lives - P2 + code:7E0615:05 + cheat + description:Infinite super energy - P1 + code:7E0516:63 + cheat + description:Infinite super energy - P2 + code:7E0616:63 + cheat + description:Infinite throw time - P1 + code:7E0580:10 + cheat + description:Infinite throw time - P2 + code:7E0680:10 + cheat + description:Have the Pipe - P1 + code:7E0514:01 + cheat + description:Have the Pipe - P2 + code:7E0614:01 + cheat + description:Have the Nunchaku - P1 + code:7E0514:02 + cheat + description:Have the Nunchaku - P2 + code:7E0614:02 + cheat + description:Have the Club - P1 + code:7E0514:03 + cheat + description:Have the Club - P2 + code:7E0614:03 + cheat + description:Have the Hammer - P1 + code:7E0514:04 + cheat + description:Have the Hammer - P2 + code:7E0614:04 + +cartridge sha256:8c47f9dc79748c0ae6c648f8480614d22eaefade065612ad1fe749fc3db4d1bc + title:Final Fight Guy (USA) + cheat + description:Infinite health + code:89AF-0401 + cheat + description:Infinite health (alt) + code:9DDF-9278 + cheat + description:Infinite time + code:1DC3-6409 + cheat + description:Infinite time (alt) + code:DBD8-FE78 + cheat + description:Hit enemies from anywhere on the screen + code:CC6D-D40D+D433-0D6F + cheat + description:Gain 9 lives every time you die + code:DDC0-ADA6 + cheat + description:No energy lost from spin kick + code:89CB-AD0C + cheat + description:Attack speed greatly increased + code:DFDF-9E88 + cheat + description:Any food restores all health + code:DDBD-6F06 + cheat + description:Enemies never get knocked down, hit them until they die + code:7E0D70:00 + cheat + description:Enemy 1 has no health + code:7E1014:00 + cheat + description:Enemy 2 has no health + code:7E10B4:00 + cheat + description:Enemy 3 has no health + code:7E1154:00 + cheat + description:Bosses have no health + code:7E11F4:00+7E11F5:00 + cheat + description:Always get Knife + code:7E1C11:00 + cheat + description:Always get Sword + code:7E1C11:02 + cheat + description:Always get Pipe + code:7E1C11:04 + cheat + description:Start on stage 2 - Subway + code:7EFFFE:01 + cheat + description:Start on stage 3 - West Side + code:7EFFFE:02 + cheat + description:Start on stage 4 - Bay Area + code:7EFFFE:04 + cheat + description:Start on stage 5 - Uptown + code:7EFFFE:05 + cheat + description:Start on bonus stage - Car + code:7EFFFE:06 + cheat + description:Start on bonus stage - Glass + code:7EFFFE:07 + +cartridge sha256:6f32355bef68d4ad58822f50074b46bcc9a68357cd2c6a5470c96bf5344f84d8 + title:Fire Striker (USA) + cheat + description:Infinite health + code:7E1333:07 + cheat + description:Infinite Power + code:7E1335:03 + cheat + description:Infinite Rest + code:7E152D:03 + +cartridge sha256:a0106f9cff7abbf25e081e2531f6d4b4aedf6f0dc8d155a66506817bff267d12 + title:Firemen, The (Europe) (En,Fr,De) + cheat + description:Infinite life + code:7E15C7:31 + cheat + description:Infinite time + code:7E1980:09 + cheat + description:Infinite Water Bombs + code:7E091A:03 + +cartridge sha256:003dba0193acc5336840307194643ca3b1f848dcfc77580b4e17c605105b27f5 + title:Firepower 2000 (USA) + cheat + description:Infinite lives + code:8263-4DDF + cheat + description:Loss of vehicle does not reduce bullet strength + code:8267-170F + cheat + description:Loss of vehicle does not reduce flame strength + code:826E-470F + cheat + description:Loss of vehicle does not reduce plasma strength + code:826D-170F + cheat + description:Loss of vehicle does not reduce laser strength + code:826F-170F + cheat + description:Loss of vehicle does not reduce ionic strength + code:8264-170F + cheat + description:Bubble shield lasts for 4 seconds instead of 12 + code:DF8B-CD07 + cheat + description:Bubble shield lasts for 8 seconds + code:D48B-CD07 + cheat + description:Bubble shield lasts for 16 seconds + code:D08B-CD07 + cheat + description:Bubble shield lasts for 32 seconds + code:D68B-CD07 + cheat + description:Bubble shield lasts for 64 seconds + code:FD8B-CD07 + cheat + description:Bubble shield on jeep lasts until end of level + code:C2CB-3FD4 + cheat + description:Bubble shield on helicopter lasts until end of level + code:C2CF-1464 + cheat + description:Start with bullet strength at 3 instead of 1 + code:D765-146F + cheat + description:Start with bullet strength at 6 + code:D165-146F + cheat + description:Start with flame strength at 3 instead of 1 + code:D761-14DF + cheat + description:Start with flame strength at 6 + code:D161-14DF + cheat + description:Start with flame strength at 0 + code:DD61-14DF + cheat + description:Start with plasma strength at 3 instead of 1 + code:D761-176F + cheat + description:Start with plasma strength at 6 + code:D161-176F + cheat + description:Start with plasma strength at 0 + code:DD61-176F + cheat + description:Start with laser strength at 1 instead of 0 + code:DF65-1FDF + cheat + description:Start with laser strength at 3 + code:D765-1FDF + cheat + description:Start with laser strength at 6 + code:D165-1FDF + cheat + description:Start with ionic strength at 1 instead of 0 + code:DF66-1DDF + cheat + description:Start with ionic strength at 3 + code:D766-1DDF + cheat + description:Start with ionic strength at 6 + code:D166-1DDF + cheat + description:Start with 1 life instead of 4 + code:DF69-1DAF + cheat + description:Start with 2 lives + code:D469-1DAF + cheat + description:Start with 3 lives + code:D769-1DAF + cheat + description:Start with 5 lives + code:D969-1DAF + cheat + description:Start with 7 lives + code:D569-1DAF + cheat + description:Start with 10 lives + code:DC69-1DAF + cheat + description:Start with 15 lives + code:DE69-1DAF + cheat + description:Start with 25 lives + code:FB69-1DAF + cheat + description:Start with 50 lives + code:7469-1DAF + cheat + description:Start with 75 lives + code:0869-1DAF + cheat + description:Start with 100 lives + code:1069-1DAF + cheat + description:Start at level 2 + code:D4B3-1764 + cheat + description:Start at level 3 + code:D7B3-1764 + cheat + description:Start at level 4 + code:D0B3-1764 + cheat + description:Start at level 5 + code:D9B3-1764 + cheat + description:Start at level 6 + code:D1B3-1764 + +cartridge sha256:4c1354337efa788169387458fa6bdbcf4be0c98369920af2bd876ad98d29070f + title:First Samurai (USA) + cheat + description:Infinite life and force + code:C9BF-D4D1 + cheat + description:Infinite lives + code:406E-D461 + cheat + description:Infinite Axe, Dagger, Grendade (slot 2 item) + code:C9B6-6700+C9BE-6D00 + cheat + description:Infinite Warp Lanterns + code:C96D-04A5 + cheat + description:Full weapon power for Dagger on pick-up + code:D783-0F09 + cheat + description:Less force picked up from enemies + code:D4C5-AFA5 + cheat + description:More force picked up from enemies + code:D6C5-AFA5 + cheat + description:Lots more power picked up from enemies + code:F9C5-AFA5 + cheat + description:Less life force from food + code:D789-AFA9 + cheat + description:More life force from food + code:FD89-AFA9 + cheat + description:Start with 9 lives + code:DB6A-676F + cheat + description:Start with 2 lives + code:D46A-676F + cheat + description:Infinite life and force (alt) + code:7E006E:3F+7E006F:3F + cheat + description:Infinite lives (alt) + code:7E0072:09 + cheat + description:Infinite Axe, Dagger, Grendade (slot 2 item) (alt) + code:7E0073:99 + cheat + description:Infinite Warp Lanterns (alt) + code:7E0078:05 + cheat + description:Infinite Bells (slot 1 item) + code:7E0074:09 + cheat + description:Have all Rune Stones + code:7E0075:05 + +cartridge sha256:064a880a8dfcf576f74ae8a17c3ec7b0a27e8cb0300a5e5959452fcc30422f14 + title:Flashback - The Quest for Identity (USA) (En,Fr,De) + cheat + description:Never lose a shield when shot (disable to kill enemies) + code:3C1F-EDAC + cheat + description:Don't die from most falls + code:8511-ED6C + cheat + description:Start with 1 shield + code:D4D4-5F78 + cheat + description:Start with 2 shields + code:D7D4-5F78 + cheat + description:Start with 3 shields + code:D0D4-5F78 + cheat + description:Start with 5 shields + code:D1D4-5F78 + cheat + description:Start with 10 shields + code:D8D4-5F78 + cheat + description:Start with 20 shields + code:F9D4-5F78 + cheat + description:Start with 50 shields + code:77D4-5F78 + cheat + description:Start with 100 shields + code:19D4-5F78 + cheat + description:Start with 50 credits + code:74F0-5F7B + cheat + description:Start with 100 credits + code:10F0-5F7B + cheat + description:Start with 250 credits + code:ECF0-5F7B + cheat + description:Start with 512 credits + code:D4F0-5DEB + cheat + description:Start with 1024 credits + code:D0F0-5DEB + +cartridge sha256:ff09d72d6241b331dc429d1cf27c04c26546f23312a22c7a14e6a4bf41ed1069 + title:Flintstones, The (USA) (En,Fr,De,Es,It) + cheat + description:Invincibility + code:2DB9-3D62+2DB3-CD02 + cheat + description:Infinite health + code:82BB-C402+C9B9-37D2 + cheat + description:Infinite lives + code:226A-ADDD + cheat + description:Infinite time + code:A2EE-CFD6 + +cartridge sha256:3d5bbc06e7e9797d937c803610c40b262c14c3f0a39e8048dd6b0b052a040fc1 + title:Flintstones, The - The Treasure of Sierra Madrock (USA) + cheat + description:Invincibility + code:DDCF-1DB7 + cheat + description:Infinite stamina + code:C28D-44FD + cheat + description:Infinite time - 1P game + code:C2A9-3D64 + cheat + description:Infinite lives - 1P game + code:C2CF-17A4 + +cartridge sha256:204ecb9b809408c23d5f5772026fc248c70612d9bf6952e6b952ed7a85640867 + title:Flying Hero - Bugyuru no Daibouken (Japan) + cheat + description:Invincibility + code:FCC4-D4D0+62C4-D400+7EC4-D460+FDC4-D4A0 + cheat + description:One hit kills + code:6D61-64D9+DDE3-0FAC + +cartridge sha256:bc6b0344a434644c391ac69a53c7720c51e2d3c5c082b8d78598ae4df100c464 + title:Foreman For Real (USA) + cheat + description:Infinite stamina - P1 + code:7E11AE:64+7E1072:27+7E043A:78+7E045A:64 + +cartridge sha256:1ce72767795f41049a1f4d2829e837a8885eb91e1c14faf1ca62d05839ebe3c9 + title:Frogger (USA) + cheat + description:Invincibility + code:7E17F4:00 + cheat + description:Infinite lives + code:7E183D:04 + cheat + description:Infinite time + code:7E078C:95 + cheat + description:Cars don't move + code:7E1886:00+7E1887:00+7E1888:00+7E1889:00+7E188A:00 + cheat + description:River objects don't move + code:7E1880:04+7E1881:04+7E1882:04+7E1883:04+7E1884:04 + +cartridge sha256:dcceb5be536c9b91bf34f65e7fcec4b55a78af0192323cf86f3b9555072037ee + title:Fun 'n Games (USA) + cheat + description:Style mode - nude legs + code:7E0F80:FE + cheat + description:Style mode - nude top + code:7E0FA3:FF + cheat + description:Style mode - nude feet + code:7E0FC6:63 + cheat + description:Style mode - nude head + code:7E0F5D:05 + +cartridge sha256:37fe99a0da8c2ca2296c35e6a08e48b9195074b2aa1955c1eed715d12196001b + title:Fushigi no Dungeon 2 - Fuurai no Shiren (Japan) + cheat + description:Gain any EXP for maximum + code:DD79-5F0B + cheat + description:Enemies start with 1 HP (If enabled when starting a new game, die, you'll restart with 1 HP, when you gain a level it should correct itself) + code:DD7D-770C+CE7D-776C+FF7D-77AC + cheat + description:Collect any Gitan for maximum + code:DD9F-7FA8 + cheat + description:Never lose Satiation + code:DD72-ED66 + cheat + description:One Arrow gains 99 + code:DD75-EFD3 + cheat + description:Smith a weapon to make it +99 + code:CBD1-8FD2+14D1-8F02 + cheat + description:Items from bartender get +99 Refinement + code:CBD8-840A+17D8-846A + +cartridge sha256:bf16c3c867c58e2ab061c70de9295b6930d63f29f81cc986f5ecae03e0ad18d2 + title:F-Zero (USA) + cheat + description:Always rank 1st + code:CB3C-0FA4+DF3C-04D4 + cheat + description:Infinite turbos + code:D484-D404 + cheat + description:Infinite spare machines + code:A96E-A4A4 + cheat + description:Start with 1 spare machine + code:DF6C-0F0A + cheat + description:Start with 5 spare machines + code:D96C-0F0A + cheat + description:Start with 9 spare machines + code:DB6C-0F0A + cheat + description:Infinite power + code:7E00C9:00+7E00CA:08 + cheat + description:Infinite turbos (alt) + code:7E0CF3:03 + cheat + description:Always rank 1st (alt) + code:7E1150:00 + cheat + description:Always boosted + code:7E0D51:08 + cheat + description:Low timer + code:7E00C1:00 + +cartridge sha256:17b24fbda9103cd8cb6f31bd6beccb4a7dfff87c8aef5e79bcc9c7d3a27623fc + title:Galaxy Wars (Japan) + cheat + description:Infinite lives + code:7E0630:05 + +cartridge sha256:ca3dd4620c692b2b8d3dd49b7dbdb1daa251ee0f7943050cc8a036e209cd7a07 + title:Ganpuru - Gunman's Proof (Japan) + cheat + description:Infinite health vs enemies/bullets + code:C266-3FBA + cheat + description:Infinite ammo for picked up guns + code:C281-4DAC + cheat + description:Infinite ammo for picked up hand weapons + code:C286-4FAC + cheat + description:Always have stronger attacks + code:DD66-14B2 + cheat + description:Always have super strong attacks + code:CB66-1FB2+7E66-14F2+6966-1422 + cheat + description:Easily get max money + code:DD68-4422 + cheat + description:Easily get max score + code:DD6D-1FB2 + cheat + description:Always have Starmine Bombs (if you have none, fire 3 off) + code:DDB5-3FFD+D42F-1F47 + cheat + description:Always get Rank S for dungeons, regardless of time taken + code:BA2B-3FC4 + +cartridge sha256:b87874a2292fe045385a2888e33009d5d2eabf55e379059aa5ef6c73b0475ff2 + title:Gekitotsu Dangan Jidousha Kessen - Battle Mobile (Japan) + cheat + description:Invincibility + code:B989-04A9+898B-AFD5+8988-AFA5 + cheat + description:Infinite health + code:898B-AFD5+8988-AFA5 + cheat + description:Infinite lives + code:C282-AF65 + cheat + description:Infinite Shields + code:8BBF-A7A5 + +cartridge sha256:fdafaa77f01a9a692411e27b3fb6045b247e5d625679b941d317a7b105f437d2 + title:George Foreman's KO Boxing (USA) (Rev 1) + cheat + description:Infinite time + code:CB62-040F+5662-046F + cheat + description:Infinite super punch after obtaining it + code:6D25-A464 + cheat + description:Time goes slower + code:566D-07DD + cheat + description:Time speeds up + code:DC6D-07DD + cheat + description:Damage inflicted by your opponent affects him (your health may slightly decrease) + code:C228-A764+5728-A7A4+622A-AFA4+572A-A4D4 + cheat + description:Start with 1/2x health - both players + code:4D6C-D70D + +cartridge sha256:b248b2122a0caf99298ebd9a4f66ad8047dbfce1e4bbac8219ba3ea9fb7488b5 + title:Ghost Chaser Densei (Japan) + cheat + description:Invincibility + code:2D83-14AD + cheat + description:Infinite health + code:82A9-3D6F + cheat + description:Infinite time + code:C2A4-47D1 + cheat + description:Hit anywhere + code:3D87-CFA4+7D87-C464+7D87-C4A4+D487-C404 + cheat + description:99 hits in bonus round + code:7E0516:63 + +cartridge sha256:a4ceb31b82ea532e6eb640fa2eda61625758e72251efa5f0ae9a984f4a98a8a0 + title:Ghoul Patrol (USA) + cheat + description:Invincibility + code:1DC0-1461+1DCC-1401 + cheat + description:Infinite lives + code:C2BD-3DD9 + cheat + description:Super powered normal arrows + code:EE61-C4A3 + cheat + description:Infinite health + code:7E1D09:0A + cheat + description:Infinite lives (alt) + code:7E1DA1:63 + cheat + description:Always have weapon + code:7E1CFE:01 + cheat + description:Infinite Keys + code:7E1D5D:63 + cheat + description:Infinite Shot 1 + code:7E1D21:63 + cheat + description:Infinite Shot 2 + code:7E1D29:63 + cheat + description:Infinite Shot 3 + code:7E1D23:63 + cheat + description:Infinite Shot 4 + code:7E1D1F:63 + cheat + description:Infinite Blue Potions + code:7E1D63:63 + cheat + description:Infinite Red Potions + code:7E1D61:63 + cheat + description:Infinite Green Potions + code:7E1D65:63 + cheat + description:Infinite Medipaks + code:7E1D71:63 + cheat + description:Infinite ? Potions + code:7E1D69:63 + cheat + description:Infinite Vials + code:7E1D67:63 + cheat + description:All victims already rescued + code:7E1E05:00 + +cartridge sha256:8796ca4de3aeffd3a494fe28e7d7e2aeb220ca652b43684f29e2cc94f02c20c4 + title:Gods (USA) + cheat + description:Shields last until at least end of the world (disable if you get stuck) + code:1DE7-31E8 + cheat + description:Infinite lives + code:C269-C1EB + cheat + description:Items you can afford in the shops are free + code:A284-35EC + cheat + description:Start with 2 lives + code:DF3C-4073 + cheat + description:Start with 6 lives + code:D93C-4073 + cheat + description:Start with 10 lives + code:DB3C-4073 + +cartridge sha256:2bb368c47189ce813ad716eef16c01cd47685cb98e2c1cb35fa6f0173c97dd7c + title:Goof Troop (USA) + cheat + description:Infinite health + code:692F-1FA7 + cheat + description:Infinite lives + code:C96F-3F6C + cheat + description:4 hearts give you a life + code:D0C0-3FA8+B3C9-3DD8 + cheat + description:2 hearts give you a life + code:D4C0-3FA8+B3C9-3DD8 + cheat + description:2 hearts from cherries + code:D4A8-4762 + cheat + description:4 hearts from bananas + code:D0A8-47A2 + cheat + description:1 heart from bananas + code:DFA8-47A2 + cheat + description:Goofy has quicker left-right movement + code:D46F-C70E+E264-C70E + cheat + description:Max has quicker left-right movement + code:D46E-170E+E26D-C70E + cheat + description:Start with 9 lives + code:DBCD-146D + cheat + description:Start with 6 lives + code:D1CD-146D + cheat + description:Start with 1 life + code:DFCD-146D + +cartridge sha256:93da752a0c76167d0907efa832367e5d14aab8e835b864f345c386071a9af718 + title:Gradius III (USA) + cheat + description:Invincibility + code:6D2D-D464 + cheat + description:Infinite Konami code use (up, up, down, down, left, right, left, right, B, A) + code:C2A9-0DDD + cheat + description:Infinite lives + code:3C8E-DDD7+3C8E-DD07 + cheat + description:Infinite credits + code:C227-6DDD + cheat + description:Hit anywhere + code:4034-A704 + cheat + description:Makes Earwig Scorpion (Stage 1 mayor) much easier to defeat + code:DFBB-A766 + cheat + description:Makes Bubble Brain (Stage 2 mayor) easier to defeat + code:DFB1-6F6C + cheat + description:Weapons status gauge remains at current level after a weapon is selected + code:3C29-0704+3C29-0764 + cheat + description:Enemies shoot at you more + code:CBAF-D7AD+DFA4-DDDD + cheat + description:Enables Arcade option in options menu + code:D78F-D4AF + cheat + description:Start with 1 life + code:DD8B-6DA4 + cheat + description:Start with 2 lives + code:DF8B-6DA4 + cheat + description:Start with 4 lives + code:D78B-6DA4 + cheat + description:Start with 5 lives + code:D08B-6DA4 + cheat + description:Start with 9 lives + code:D68B-6DA4 + cheat + description:Start with 16 lives + code:DE8B-6DA4 + cheat + description:Start with 31 lives + code:F38B-6DA4 + cheat + description:Start with 1 credit (1P game) + code:DFC3-DF0D + cheat + description:Start with 2 credits + code:D4C3-DF0D + cheat + description:Start with 6 credits + code:D1C3-DF0D + cheat + description:Start with 7 credits + code:D5C3-DF0D + cheat + description:Start with 8 credits + code:D6C3-DF0D + cheat + description:Start with 9 credits + code:DBC3-DF0D + cheat + description:Infinite credits (alt) + code:00D230:AD + cheat + description:Infinite continues + code:7E1E06:03 + cheat + description:Infinite Forcefield + code:7E0346:02+7E0350:02 + cheat + description:Weapons status gauge remains at current level after a weapon is selected (alt) + code:00D95D:EA+00D95E:EA + cheat + description:Enemies die automatically + code:7E00DC:0B + cheat + description:Have Mega Crush + code:7E00B0:07 + cheat + description:Have Max Speed + code:7E00B2:05 + cheat + description:Have support upgrade - Missile + code:7E00B4:0B + cheat + description:Have support upgrade - Spread Bomb + code:7E00B4:0C + cheat + description:Have support upgrade - 2-Way Missile + code:7E00B4:0D + cheat + description:Have gun - Double + code:7E00B6:02 + cheat + description:Have gun - Tailgun + code:7E00B6:03 + cheat + description:Have gun - Back Double + code:7E00B6:04 + cheat + description:Have gun - Verticle + code:7E00B6:05 + cheat + description:Have gun - Twin Laser + code:7E00B6:06 + cheat + description:Have gun - Laser + code:7E00B6:07 + cheat + description:Have gun - Charged Laser + code:7E00B6:09 + cheat + description:Have gun - Laser (2nd) + code:7E00B6:0A + cheat + description:Have 99 million points - P1 + code:7E1F47:99 + cheat + description:Have 99 million points - P2 + code:7E1F4B:99 + +cartridge sha256:f8c02a0b996d33c0a64c30fb76b80f8e441d67b8ecebb6940bb1171760aa444c + title:Great Battle II, The - Last Fighter Twin (Japan) + cheat + description:Invincibility + code:CB30-07AD+DF39-0DDD+6239-0D0D+9839-0D6D+D039-0DAD + cheat + description:Infinite health + code:89BB-AFAF + cheat + description:Infinite lives + code:29C8-670D + cheat + description:One hit kills + code:6D88-04DF + cheat + description:Invincibility (alt) + code:7E045B:01 + cheat + description:Infinite health (alt) + code:7E0454:60 + cheat + description:Infinite lives (alt) + code:7E00D4:03 + +cartridge sha256:10a8d4a4eeefb124693ea72d4613cfd210a332d8ec2fdfcd64695427bf2f65d0 + title:Great Battle III, The (Japan) + cheat + description:Invincibility + code:2D80-0DDF+2D80-0F0F + cheat + description:Infinite health + code:8985-D76D + cheat + description:Infinite lives + code:2981-04A7 + cheat + description:One hit kills + code:6DAC-DDA7 + cheat + description:Invincibility (alt) + code:7E00D4:03 + cheat + description:Infinite health (alt) + code:7E0464:48 + cheat + description:Infinite lives (alt) + code:7E00E4:03 + +cartridge sha256:b5492aea296ee4bfcd2c677fbec5153fd4c4db758c835b372ef750cf2399649b + title:Great Circus Mystery Starring Mickey & Minnie, The (USA) + cheat + description:Invincibility against enemies + code:6D94-E764 + cheat + description:Invincibility against ground hazards + code:6DF3-5FA0 + cheat + description:Infinite Vacuum + code:C9FB-5769 + cheat + description:Infinite Bullets + code:C9FB-8FA9 + cheat + description:Collect one coin for 999 + code:DD9D-5D07 + +cartridge sha256:f921297c361f16ad3f1257e91829638fc795f9323172015d7237ed648c8f7515 + title:GunForce - Battle Fire Engulfed Terror Island (USA) + cheat + description:Invincibility + code:69BD-A4A1+CBBD-A401 + cheat + description:Infinite ammo + code:C2E7-AFAF + cheat + description:Hit anywhere + code:C2B7-AFD4+DDB8-070F+DDB8-0F6F+DDBB-04AF+DDBC-0D0F + cheat + description:Invincibility (alt) + code:7E0055:B1 + cheat + description:Infinite time (enable during gameplay) + code:7E0028:09+7E0029:09 + cheat + description:Infinite lives - P1 + code:7E0051:09 + cheat + description:Infinite lives - P2 + code:7E0052:09 + cheat + description:Infinite continues - P1 + code:7E0053:09 + cheat + description:Infinite continues - P2 + code:7E0054:09 + cheat + description:Have Rapid Fire + code:7E0057:FF + cheat + description:Have regular gun + code:7E9015:01 + cheat + description:Have Laser gun + code:7E9015:04 + cheat + description:Have Bazooka + code:7E9015:07 + cheat + description:Have Flamethrower + code:7E9015:0E + +cartridge sha256:5a6deb5617e86a9f4b981031e939510e30c5c8ad047f5f012e40442113fd28c2 + title:Hagane - The Final Conflict (USA) + cheat + description:Invincibility + code:1D0B-576D + cheat + description:Infinite time + code:6D6F-8D0F + cheat + description:Infinite Bombs + code:3CBF-8FDD + cheat + description:Infinite Daggers + code:3CB9-5F6D + cheat + description:Infinite special attacks + code:3C68-EDD4 + cheat + description:Infinite lives + code:3C62-540F + cheat + description:One hit kills + code:DD0D-770D + cheat + description:Start with 9 lives + code:DB63-57DD + cheat + description:Start with 9 special attack points + code:DB6E-5DDD + cheat + description:Start with maximum health points + code:D963-5FDD + cheat + description:Start on stage 2 - Fortress Of Doom + code:CB6A-5D0D+DF6A-5D6D + cheat + description:Start on stage 3 - Violated Heavens + code:CB6A-5D0D+D46A-5D6D + cheat + description:Start on stage 4 - Cry Of The Spirits + code:CB6A-5D0D+D76A-5D6D + cheat + description:Start on stage 5 - Into The Darkness + code:CB6A-5D0D+D06A-5D6D + +cartridge sha256:de1cf1512e48473b03adb87b7504f394e8b330b346bac24044f833d83609799a + title:HAL's Hole in One Golf (USA) + cheat + description:No penalty if you land in water or out of bounds + code:4A6C-6D69 + cheat + description:Always start hole with 1-shot penalty + code:DF6F-0D00 + cheat + description:Max 7 strokes per hole + code:D56C-A401 + cheat + description:Max 5 strokes per hole + code:D96C-A401 + +cartridge sha256:6e2a02a8944c19db3da76d2646f232fbe3ed039bc7d44cc03910814fa77a7acf + title:Harley's Humongous Adventure (USA) + cheat + description:Protection against some hazards + code:C2C0-0DB5 + cheat + description:Infinite ammo + code:DD87-A4B0 + cheat + description:Infinite lives + code:C2C8-07B5 + cheat + description:Infinite Jet Fuel on pick-up + code:DDCD-6DF5 + cheat + description:Infinite time on Vent level + code:3C83-ADA4 + cheat + description:Any fuel power-up gives maximum amount + code:DDC4-6495 + cheat + description:Press X on the title screen with the house to get level select menu + code:D43E-046F + cheat + description:Get only 5 ammo from a weapon power-up + code:D98D-DDB9 + cheat + description:Get 20 ammo from a weapon power-up + code:4D8D-DDB9 + cheat + description:Get 30 ammo from a weapon power-up + code:7D8D-DDB9 + cheat + description:Get 40 ammo from a weapon power-up + code:0D8D-DDB9 + cheat + description:Get 50 ammo from a weapon power-up + code:9D8D-DDB9 + cheat + description:20 seconds to collect power-ups on level 1 + code:F08C-A704 + cheat + description:60 seconds to collect power-ups on level 1 + code:7A8C-A704 + cheat + description:90 seconds to collect power-ups on level 1 + code:9C8C-A704 + cheat + description:60 seconds to complete the Vent level + code:7A88-A7D4 + cheat + description:Start with maximum fuel on every level + code:6DCF-04B1 + cheat + description:Start with 4 hearts + code:D6CF-ADB1 + cheat + description:Start with 5 hearts + code:DCCF-ADB1 + cheat + description:Start with 10 of every weapon + code:FD22-6415 + cheat + description:Start with 25 of every weapon + code:4922-6415 + cheat + description:Start with 50 of every weapon + code:9D22-6415 + cheat + description:Start with 99 of every weapon + code:BB22-6415 + cheat + description:Start with 2 lives + code:DFCF-A7F1 + cheat + description:Start with 6 lives + code:D9CF-A7F1 + cheat + description:Start with 11 lives + code:FDCF-A7F1 + cheat + description:Start with 26 lives + code:49CF-A7F1 + cheat + description:Start with 51 lives + code:9DCF-A7F1 + cheat + description:Start with 100 lives + code:BBCF-A7F1 + cheat + description:Infinite health against most enemies + code:7EAB45:32 + cheat + description:Start with all weapons + code:09DED9:FF + cheat + description:Infinite weapons on pick-up + code:7EAB54:9A + cheat + description:Infinite Air + code:7E24B2:FF + cheat + description:Infinite Fuel on pick-up (disable to complete level) + code:7E24BC:FF + cheat + description:Infinte Nuts + code:7E24AC:99 + cheat + description:Infinite Invincibility Spray + code:7EAB44:84 + cheat + description:Infinite time + code:7E1C3B:64 + cheat + description:Moon-jump + code:7E0283:02 + +cartridge sha256:73a3aa87ddd5ce5df5ba51292316f42b6e128280179b0a1b11b4dcddc17d4163 + title:Harvest Moon (USA) + cheat + description:Can access all items temporarily + code:C980-3460 + cheat + description:Don't lose stamina + code:C22E-4DD0 + cheat + description:Go to bed to get 200 stamina + code:CB68-34A6+A668-37D6+3C68-3706 + cheat + description:With 1 or more wood, take some to get 999 + code:6D87-CFDA + cheat + description:With 0 wood, take some to get 999 + code:F987-CDDA + cheat + description:Fencing doesn't break when it storms + code:6DC5-3DAB + cheat + description:Go to sleep to put a bell plant next to the stable + code:FD69-47DB + cheat + description:Go to sleep to enable the egg festival prize + code:DB6B-3F6B+DD6B-3FAB+FD6B-34DB + cheat + description:Town always performs Flower Festival + code:DD2D-37AA+242F-3D0A + +cartridge sha256:7c34908526db2a634216fab0276c42a8e4e22d59c728cd586200142a12dd2c2c + title:Home Alone (USA) + cheat + description:Infinite power + code:C220-D464 + cheat + description:Infinite lives + code:DD21-DFD4 + cheat + description:Infinite Baseballs, Slingshot and Rifle ammo + code:DD2A-A76F + cheat + description:Power boost on jumps + code:3DB1-07D5 + cheat + description:Super power boost on jumps + code:ADB1-07D5 + cheat + description:Need 1 item (instead of 24) to complete level 1 + code:DF23-A764 + cheat + description:Need 5 items to complete level 1 + code:D923-A764 + cheat + description:Need 10 items to complete level 1 + code:FD23-A764 + cheat + description:Need 15 items to complete level 1 + code:F923-A764 + cheat + description:Need 20 items to complete level 1 + code:4D23-A764 + cheat + description:Need 1 item (instead of 30) to complete level 2 + code:DF23-A7A4 + cheat + description:Need 5 items to complete level 2 + code:D923-A7A4 + cheat + description:Need 10 items to complete level 2 + code:FD23-A7A4 + cheat + description:Need 15 items to complete level 2 + code:F923-A7A4 + cheat + description:Need 20 items to complete level 2 + code:4D23-A7A4 + cheat + description:Need 25 items to complete level 2 + code:4923-A7A4 + cheat + description:Need 1 item (instead of 35) to complete level 3 + code:DF2E-ADD4 + cheat + description:Need 5 items to complete level 3 + code:D92E-ADD4 + cheat + description:Need 10 items to complete level 3 + code:FD2E-ADD4 + cheat + description:Need 15 items to complete level 3 + code:F92E-ADD4 + cheat + description:Need 20 items to complete level 3 + code:4D2E-ADD4 + cheat + description:Need 25 items to complete level 3 + code:492E-ADD4 + cheat + description:Need 1 item (instead of 35) to complete level 4 + code:DF2E-AD04 + cheat + description:Need 5 items to complete level 4 + code:D92E-AD04 + cheat + description:Need 10 items to complete level 4 + code:FD2E-AD04 + cheat + description:Need 15 items to complete level 4 + code:F92E-AD04 + cheat + description:Need 20 items to complete level 4 + code:4D2E-AD04 + cheat + description:Need 25 items to complete level 4 + code:492E-AD04 + cheat + description:Extra life with 1 pizza slice instead of 8 + code:DF66-04A7 + cheat + description:Extra life with 2 pizza slices + code:D466-04A7 + cheat + description:Extra life with 3 pizza slices + code:D766-04A7 + cheat + description:Extra life with 4 pizza slices + code:D066-04A7 + cheat + description:Extra life with 5 pizza slices + code:D966-04A7 + cheat + description:Extra life with 6 pizza slices + code:D166-04A7 + cheat + description:Extra life with 7 pizza slices + code:D566-04A7 + cheat + description:Start with 1 life instead of 3 + code:DF2B-AFD4 + cheat + description:Start with 2 lives + code:D42B-AFD4 + cheat + description:Start with 5 lives + code:D92B-AFD4 + cheat + description:Start with 9 lives + code:DB2B-AFD4 + cheat + description:Start with 25 lives + code:492B-AFD4 + cheat + description:Start with 50 lives + code:9D2B-AFD4 + cheat + description:Start with 99 lives + code:BB2B-AFD4 + cheat + description:Start on level 2 + code:DF69-DFAD+AB69-D40D+D769-D46D + cheat + description:Start on level 3 + code:D469-DFAD+AB69-D40D+D769-D46D + cheat + description:Start on level 4 + code:D769-DFAD+AB69-D40D+D769-D46D + +cartridge sha256:27eaccb4eea93832639565a664bf3561ed5a11ac025d377a3f33262d851c1b2b + title:Home Alone 2 - Lost in New York (USA) + cheat + description:Infinite power (some things can still kill you) + code:C22E-AF9D + cheat + description:Infinite ammo + code:3CB7-6DA4 + cheat + description:Infinite lives + code:C264-D464 + cheat + description:Dart guns have 50 shots + code:7427-AF2F+7429-AD9F + cheat + description:Extra life from 1 pizza slice instead of 6 + code:DF2B-AFBF + cheat + description:Extra life from 2 pizza slices + code:D42B-AFBF + cheat + description:Extra life from 3 pizza slices + code:D72B-AFBF + cheat + description:Extra life from 4 pizza slices + code:D02B-AFBF + cheat + description:Extra life from 5 pizza slices + code:D92B-AFBF + cheat + description:Start with 1 life instead of 3 + code:DFB5-6FA7 + cheat + description:Start with 5 lives + code:D9B5-6FA7 + cheat + description:Start with 9 lives + code:DBB5-6FA7 + cheat + description:Start with 25 lives + code:FBB5-6FA7 + cheat + description:Start with 50 lives + code:74B5-6FA7 + cheat + description:Start with 99 lives + code:17B5-6FA7 + +cartridge sha256:48a3ac52e2c9128abc2dc60e07817a51898e8a93be0d51d6f541a8635263a089 + title:Home Improvement (USA) + cheat + description:Invincibility + code:6D62-4B82+6D69-1CEA + cheat + description:Infinite lives + code:CB69-1FDE + cheat + description:Infinite Nut Bolts + code:C9BC-3673+C9C4-4683+C26F-468A + +cartridge sha256:acad4c594f156e0f30dec2532b35fcb3bab800e08263377634e2d96dfd055f3e + title:Hook (USA) + cheat + description:Infinite power (disable if you get stuck) + code:3CA5-D70F + cheat + description:Infinite time + code:A268-6F03 + cheat + description:Time starts at 7 min - stage 1 + code:D56B-ADA2 + cheat + description:Time starts at 3 min - stage 1 + code:D76B-ADA2 + cheat + description:Start with 3 power leaves + code:D066-0FDD + cheat + description:Start with 1 leaf (shows 2, but you can only fill 1) + code:D466-0FDD + cheat + description:Infinite power (alt) + code:7EF7C1:03 + cheat + description:Infinite lives + code:7E1F00:03 + cheat + description:Infinite flying + code:7E1F07:80+7E1F08:01 + cheat + description:Infinite time (alt) + code:7E1F14:59 + +cartridge sha256:ba6cb0d64cef410c5dd517ce0424fc0942a15b0df0274903939c043f3ac79d39 + title:Humans, The (Europe) + cheat + description:Infinite lives + code:7E010B:0C + cheat + description:Infinite time (disable at end of level) + code:7E0122:78+7E0123:00 + +cartridge sha256:a03528344d40bf800cdbde2dd240b30442cec7aea6026fbbe312a7c36bf0f74a + title:Hunt for Red October, The (USA) + cheat + description:Infinite Bombs + code:C2AE-1404 + cheat + description:Infinite ECMs + code:C2AC-34D4 + cheat + description:Infinite SAMs + code:C2AB-CFD4 + cheat + description:Infinite SSMs + code:C2A7-3D64 + cheat + description:Infinite Torpedoes + code:C2A0-1D64 + cheat + description:Start with 0 Bombs instead of 40 + code:DD34-4761 + cheat + description:Start with 99 Bombs + code:1734-4761 + cheat + description:Start with 0 Torpedoes instead of 60 + code:DD3F-47D1 + cheat + description:Start with 99 Torpedoes + code:173F-47D1 + cheat + description:Start with 0 Surface-to-Air Missiles (SAMs) instead of 25 + code:DD34-44D1 + cheat + description:Start with 50 SAMs + code:7434-44D1 + cheat + description:Start with 99 SAMs + code:1734-44D1 + cheat + description:Start with 0 Surface-to-Surface Missiles (SSMs) instead of 25 + code:DD34-4D61 + cheat + description:Start with 50 SSMs + code:7434-4D61 + cheat + description:Start with 99 SSMs + code:1734-4D61 + cheat + description:Start with 0 Electronic Countermeasures (ECMs) instead of 2 + code:DD3F-4F61 + cheat + description:Start with 50 ECMs + code:743F-4F61 + cheat + description:Start with 99 ECMs + code:173F-4F61 + cheat + description:Start in theatre I - Caribbean + code:D4BA-1F64 + cheat + description:Start in theatre II - North Pacifi + code:D1BA-1F64 + cheat + description:Start in theatre III - Mediterranean + code:DABA-1F64 + cheat + description:Start on the final mission - Return to the USSR + code:FDBA-1F64 + +cartridge sha256:41cc900d2461a8dc4706640e493885ddf85db04d8dffceebf7a0ed89cc983d8d + title:Hurricanes (USA) + cheat + description:Invincibility + code:7E0CA2:FF + cheat + description:Infinite health + code:7E0D0E:2C + cheat + description:Infinite time + code:7E1252:09 + cheat + description:Infinite lives + code:7E0D16:09 + +cartridge sha256:f57c49cc3e4c5e34929e12658db0de8794265c517e42f3c518bb1466ba46f14a + title:HyperZone (USA) + cheat + description:Infinite power + code:4A8A-DFD1 + cheat + description:Restore energy more quickly + code:D76A-D7D5 + cheat + description:Restore energy more slowly + code:DD6A-D7D5 + cheat + description:Start with 8 lives + code:D5C4-DFD1 + cheat + description:Start with 1 life + code:DDC4-DFD1 + +cartridge sha256:fa143784fd20721d61101920e6aae9b7f5012b8157b1ce0c7ea83ea6c875d84d + title:Ignition Factor, The (USA) + cheat + description:Infinite health + code:7E0669:F9 + cheat + description:Max health + code:7E069A:F9 + cheat + description:Always have full abilities regardless of how many items you carry + code:7E0698:00 + cheat + description:Infinite Air Tank + code:7E0690:B4 + cheat + description:Infinite CO2 Bombs + code:7E0695:B4 + cheat + description:Infinite Fire Trucks + code:7E0697:03 + cheat + description:Infinite Blue (electrical) Extinguisher + code:7E068F:B4 + cheat + description:Infinite Green (chemical) Extinguisher + code:7E068E:B4 + cheat + description:Infinite Red Extinguisher + code:7E068D:B4 + cheat + description:Infinite Plastic Explosives + code:7E0696:B4 + cheat + description:Infinite time - minutes + code:7E1CBA:00 + cheat + description:Infinite time - seconds + code:7E1CB9:00 + cheat + description:Infinite time - milliseconds + code:7E1CB8:00 + cheat + description:Have Green (chemical) Extinguisher in slot 1 + code:7E14C2:02 + cheat + description:Have Blue (electrical) Extinguisher in slot 2 + code:7E14C6:04 + cheat + description:Have Oxygen Tank and Mask in slot 3 + code:7E14CA:06 + cheat + description:Have Chainsaw in slot 4 + code:7E14CE:08 + cheat + description:Have Rope in slot 4 + code:7E14CE:0A + cheat + description:Have Axe in slot 4 + code:7E14CE:0C + cheat + description:Have Pole in slot 4 + code:7E14CE:0E + cheat + description:Have CO2 Bombs in slot 4 + code:7E14CE:10 + cheat + description:Have Plastic Explosives in slot 4 + code:7E14CE:12 + cheat + description:Haev Fossile in slot 4 + code:7E14CE:14 + cheat + description:Have First Aid Kit in slot 4 + code:7E14CE:26 + +cartridge sha256:32adc048fd89228a4310c03df243e83de7d436cdb2460b4cc83ade20d359b2bd + title:Illusion of Gaia (USA) + cheat + description:Infinite HP + code:C2A5-44A2 + cheat + description:Less charge time for psycho dash + code:D98F-4F0C + cheat + description:Less charge time for dark friar + code:D98B-4DDC + cheat + description:Super run left/right only + code:D9AA-1F0B+E8A5-14AB + cheat + description:Super run up/down only + code:EAA7-1D6B+D0A3-446B + cheat + description:Get 2x the energy from herbs + code:FD6B-47A3 + cheat + description:Get 3x the energy from herbs + code:F66B-47A3 + cheat + description:Red Jewel 50 check passes + code:DDA0-3D37 + cheat + description:Red Jewel 30 check passes + code:DDA7-3447 + cheat + description:Red Jewel 20 check passes + code:DDA4-3F37 + cheat + description:Red Jewel 12 check passes + code:DDAF-3FC7 + cheat + description:Red Jewel 08 check passes + code:DDAD-3F17 + cheat + description:Red Jewel 05 check passes + code:DDAE-CF47 + cheat + description:Red Jewel 03 check passes + code:DDA3-CD37 + cheat + description:Start with max HP + code:EE61-440D + cheat + description:Start with a lot more energy + code:F061-44DD + cheat + description:Start with 20 strength points + code:F065-4D0D + cheat + description:Start with 50 strength points + code:7465-4D0D + cheat + description:Start with 80 strength points + code:9D65-4D0D + cheat + description:Infinite HP + code:7E0ACD:32+7E0ACE:32 + cheat + description:Max HP + code:7E0ACA:32+7E0ACB:03 + cheat + description:Max Strength + code:7E0ADE:63 + cheat + description:Max Defense + code:7E0ADC:63 + cheat + description:Can always attack + code:7E09AE:00 + cheat + description:One hit kills + code:7E0ADE:FF+7E0ADF:FF + cheat + description:Play as Will + code:7E0AD4:00 + cheat + description:Play as Knight + code:7E0AD4:01 + cheat + description:Play as Shade + code:7E0AD4:02 + cheat + description:Walk through walls + code:82E301:AF+82E304:9B + cheat + description:Can always attack + code:7E09AE:00 + cheat + description:Have all Statues + code:7E0A1F:BF + cheat + description:Have Red Jewel - slot 1 + code:7E0AB4:01 + cheat + description:Have Red Jewel - slot 16 + code:7E0AC3:01 + cheat + description:Have Prison Key - slot 1 + code:7E0AB4:02 + cheat + description:Have Prison Key - slot 16 + code:7E0AC3:02 + cheat + description:Have Incan Statue A - slot 1 + code:7E0AB4:03 + cheat + description:Have Incan Statue A - slot 16 + code:7E0AC3:03 + cheat + description:Have Incan Statue B - slot 1 + code:7E0AB4:04 + cheat + description:Have Incan Statue B - slot 16 + code:7E0AC3:04 + cheat + description:Have Incan Melody - slot 1 + code:7E0AB4:05 + cheat + description:Have Incan Melody - slot 16 + code:7E0AC3:05 + cheat + description:Have Herb - slot 1 + code:7E0AB4:06 + cheat + description:Have Herb - slot 16 + code:7E0AC3:06 + cheat + description:Have Blue Block - slot 1 + code:7E0AB4:07 + cheat + description:Have Blue Block - slot 16 + code:7E0AC3:07 + cheat + description:Have Wind Melody - slot 1 + code:7E0AB4:08 + cheat + description:Have Wind Melody - slot 16 + code:7E0AC3:08 + cheat + description:Have Lola's Melody - slot 1 + code:7E0AB4:09 + cheat + description:Have Lola's Melody - slot 16 + code:7E0AC3:09 + cheat + description:Have Meat - slot 1 + code:7E0AB4:0A + cheat + description:Have Meat - slot 16 + code:7E0AC3:0A + cheat + description:Have Mine Key A - slot 1 + code:7E0AB4:0B + cheat + description:Have Mine Key A - slot 16 + code:7E0AC3:0B + cheat + description:Have Mine Key B - slot 1 + code:7E0AB4:0C + cheat + description:Have Mine Key B - slot 16 + code:7E0AC3:0C + cheat + description:Have Memory Melody - slot 1 + code:7E0AB4:0D + cheat + description:Have Memory Melody - slot 16 + code:7E0AC3:0D + cheat + description:Have Crystal Ball - slot 1 + code:7E0AB4:0E + cheat + description:Have Crystal Ball - slot 16 + code:7E0AC3:0E + cheat + description:Have Elevator Key - slot 1 + code:7E0AB4:0F + cheat + description:Have Elevator Key - slot 16 + code:7E0AC3:0F + cheat + description:Have Palace Key - slot 1 + code:7E0AB4:10 + cheat + description:Have Palace Key - slot 16 + code:7E0AC3:10 + cheat + description:Have Purify Stone - slot 1 + code:7E0AB4:11 + cheat + description:Have Purify Stone - slot 16 + code:7E0AC3:11 + cheat + description:Have Statue of Hope - slot 1 + code:7E0AB4:12 + cheat + description:Have Statue of Hope - slot 16 + code:7E0AC3:12 + cheat + description:Have Rama Statue - slot 1 + code:7E0AB4:13 + cheat + description:Have Rama Statue - slot 16 + code:7E0AC3:13 + cheat + description:Have Magic Dust - slot 1 + code:7E0AB4:14 + cheat + description:Have Magic Dust - slot 16 + code:7E0AC3:14 + cheat + description:Have Blue Journal - slot 1 + code:7E0AB4:15 + cheat + description:Have Blue Journal - slot 16 + code:7E0AC3:15 + cheat + description:Have Lance's Leter - slot 1 + code:7E0AB4:16 + cheat + description:Have Lance's Leter - slot 16 + code:7E0AC3:16 + cheat + description:Have Necklace Stone - slot 1 + code:7E0AB4:17 + cheat + description:Have Necklace Stone - slot 16 + code:7E0AC3:17 + cheat + description:Have Will - slot 1 + code:7E0AB4:18 + cheat + description:Have Will - slot 16 + code:7E0AC3:18 + cheat + description:Have Tea Pot - slot 1 + code:7E0AB4:19 + cheat + description:Have Tea Pot - slot 16 + code:7E0AC3:19 + cheat + description:Have Mushroom Drop - slot 1 + code:7E0AB4:1A + cheat + description:Have Mushroom Drop - slot 16 + code:7E0AC3:1A + cheat + description:Have Bag of Gold - slot 1 + code:7E0AB4:1B + cheat + description:Have Bag of Gold - slot 16 + code:7E0AC3:1B + cheat + description:Have Black Glasses - slot 1 + code:7E0AB4:1C + cheat + description:Have Black Glasses - slot 16 + code:7E0AC3:1C + cheat + description:Have Gorgon Flower - slot 1 + code:7E0AB4:1D + cheat + description:Have Gorgon Flower - slot 16 + code:7E0AC3:1D + cheat + description:Have Heiroglyph 1 - slot 1 + code:7E0AB4:1E + cheat + description:Have Heiroglyph 1 - slot 16 + code:7E0AC3:1E + cheat + description:Have Heiroglyph 2 - slot 1 + code:7E0AB4:1F + cheat + description:Have Heiroglyph 2 - slot 16 + code:7E0AC3:1F + cheat + description:Have Heiroglyph 3 - slot 1 + code:7E0AB4:20 + cheat + description:Have Heiroglyph 3 - slot 16 + code:7E0AC3:20 + cheat + description:Have Heiroglyph 4 - slot 1 + code:7E0AB4:21 + cheat + description:Have Heiroglyph 4 - slot 16 + code:7E0AC3:21 + cheat + description:Have Heiroglyph 5 - slot 1 + code:7E0AB4:22 + cheat + description:Have Heiroglyph 5 - slot 16 + code:7E0AC3:22 + cheat + description:Have Heiroglyph 6 - slot 1 + code:7E0AB4:23 + cheat + description:Have Heiroglyph 6 - slot 16 + code:7E0AC3:23 + cheat + description:Have Aura - slot 1 + code:7E0AB4:24 + cheat + description:Have Aura - slot 16 + code:7E0AC3:24 + cheat + description:Have Lola's Letter - slot 1 + code:7E0AB4:25 + cheat + description:Have Lola's Letter - slot 16 + code:7E0AC3:25 + cheat + description:Have Father's Journal - slot 1 + code:7E0AB4:26 + cheat + description:Have Father's Journal - slot 16 + code:7E0AC3:26 + cheat + description:Have Crystal Ring - slot 1 + code:7E0AB4:27 + cheat + description:Have Crystal Ring - slot 16 + code:7E0AC3:27 + cheat + description:Have Red Apple - slot 1 + code:7E0AB4:28 + cheat + description:Have Red Apple - slot 16 + code:7E0AC3:28 + +cartridge sha256:4dc2b5de98e9109583d9b61b38d26a8216af4dba246ef71350122213630562d0 + title:Imperium (USA) + cheat + description:Invincibility against lesser robots, weapons and lasers + code:1D34-D4A1+1DC3-DDF7 + cheat + description:Start with 1 life point + code:DFA2-D4A4 + cheat + description:Start with 3 life points + code:D7A2-D4A4 + cheat + description:Start with 5 bombs + code:D9BD-64D7 + cheat + description:Start with 9 bombs + code:DBBD-64D7 + +cartridge sha256:c41150c0e84055801377fb7cb273cc51ca442b269ca6287cadf514f553e34750 + title:Incantation (USA) + cheat + description:Infinite energy + code:C234-CFD7 + cheat + description:Infinite lives + code:C2A0-3FD7 + cheat + description:Invincibility (blinking) + code:7E07FC:5F + cheat + description:Infinite energy (alt) + code:7E1115:30 + cheat + description:Infinite lives (alt) + code:7E0846:64 + cheat + description:Super-jump with lunar descent + code:7E163D:00 + cheat + description:3 wheat for toll + code:7E0E69:03 + cheat + description:Max bonus + code:7E083C:5A+7E083E:63 + cheat + description:Have larger shot + code:7E07E8:D4+7E07EA:1A + +cartridge sha256:0415adfe80977485f84cdffaaa79f18c91c004c7dba202b4cf9a94eb11adeada + title:Incredible Crash Dummies, The (USA) + cheat + description:Invincibility (blinking) + code:7E1338:37 + cheat + description:Infinite health + code:7E03B6:05 + cheat + description:Infinite lives + code:7E03B5:05 + cheat + description:Infinite time (disable at end of level) + code:7E04A6:3B + cheat + description:Infinite spanners + code:7E04A0:0A + cheat + description:Infinite wrenches (disable at end of level) + code:7E04A0:05 + cheat + description:Infinite airbag once obtained + code:7E0492:C7 + cheat + description:Infinite lightning once obtained + code:7E0490:C7 + cheat + description:Start at Parking Level 1 + code:7E03B9:01 + cheat + description:Start at Crash Center + code:7E03B9:02 + cheat + description:Start at Crash Center Boss + code:7E03B9:03 + cheat + description:Start at Construction Site 1 + code:7E03B9:04 + cheat + description:Start at Construction Site 2 + code:7E03B9:05 + cheat + description:Start at Construction Site Boss + code:7E03B9:06 + cheat + description:Start at Artillery Range 1 + code:7E03B9:07 + cheat + description:Start at Military Complex + code:7E03B9:08 + cheat + description:Start at Military Complex Boss + code:7E03B9:09 + cheat + description:Start at Junk Kastle + code:7E03B9:0A + cheat + description:Start at Junk Kastle Boss + code:7E03B9:0B + cheat + description:Start at Title Screen + code:7E03B9:0C + cheat + description:Start at Credits + code:7E03B9:0D + cheat + description:Start at Parking Level 2 + code:7E03B9:0E + cheat + description:Start at Vehicle Crash Test 1 'car' + code:7E03B9:0F + cheat + description:Start at Vehicle Crash Test 2 'bulldozer' + code:7E03B9:10 + cheat + description:Start at Artillery Range 2 + code:7E03B9:11 + cheat + description:Start at Vehicle Crash Test 3 'tank' + code:7E03B9:12 + +cartridge sha256:8d170628d2d2fdf142bb82ad80e908bba54c45fa33241c779b8eafaf1b21171f + title:Incredible Hulk, The (USA) + cheat + description:Infinite health + code:8260-1465+C2E9-44DF + cheat + description:Infinite transformation capsules on pick-up + code:C96D-CDC6 + cheat + description:Health doesn't decrease when Hulked-out + code:C260-4746 + cheat + description:Get 4 shots from gun + code:D0BC-173B + cheat + description:Get 9 shots from gun + code:DBBC-173B + cheat + description:Get 20 shots from gun + code:F0BC-173B + cheat + description:Get 20 seconds from time icon + code:4DB0-1F4B + cheat + description:Get 40 seconds from time icon + code:0DB0-1F4B + cheat + description:2x energy from gamma capsules + code:F3BE-144B + cheat + description:Gamma capsules act as mega-gamma capsules + code:DDB8-171B + cheat + description:Super-jump (sometimes) + code:DA25-34A7+DA34-47AD + cheat + description:Mega-jump (sometimes) + code:FB25-34A7+FB34-47AD + cheat + description:Mega damage from Hulk's uppercut + code:DCB7-44D0 + cheat + description:Mega damage from Hulk's head butt + code:DCB1-4FD0 + cheat + description:4x damage from Hulk's uppercut + code:D0B7-44D0 + cheat + description:4x damage from Hulk's head-butt + code:D0B1-4FD0 + cheat + description:Start with 1 life + code:DFBD-CD6F + cheat + description:Start with 6 lives + code:D1BD-CD6F + cheat + description:Start with 9 lives + code:DBBD-CD6F + cheat + description:Start on level 2 + code:DDB2-1F0F + cheat + description:Start on level 3 + code:4DB2-1F0F + cheat + description:Start on level 4 + code:0DB2-1F0F + cheat + description:Start on level 5 + code:6DB2-1F0F + cheat + description:Infinite and max health + code:7E0718:63 + cheat + description:Infinite lives + code:7E00C0:09 + +cartridge sha256:cf611b40f9570e8fcfdc21db623965da62561e8ca82ded59e432ba6fb0bfb562 + title:Indiana Jones' Greatest Adventures (USA) + cheat + description:Invincibility + code:62A7-1764+2D80-CDDF + cheat + description:Infinite lives + code:C2C2-37A4 + cheat + description:Infinite Bombs + code:C2B6-370F + cheat + description:Infinite Grenades + code:C2B6-370F + cheat + description:Infinite continues + code:3CAB-CE82+F0BC-173B + cheat + description:Hearts don't restore health + code:C2B6-440F + cheat + description:Can't collect Grenades + code:C2B9-37DF + cheat + description:Start with very little health + code:DFC1-3707 + cheat + description:Start with about 1/2 health + code:D7C1-3707 + cheat + description:Start with more health (ignore health meter) + code:DEC1-3701 + cheat + description:Start with 5 Grenades + code:D9C7-CF0F + cheat + description:Start with 9 Grenades + code:DBC7-CF0F + cheat + description:Start with 15 Grenades + code:DEC7-CF0F + cheat + description:Start with 2 lives + code:DFCC-1E83 + cheat + description:Start with 5 lives + code:D0CC-1E83 + cheat + description:Start with 10 lives + code:DBCC-1E83 + cheat + description:Start with no continues + code:D1C8-13E3 + cheat + description:Infinite health + code:7E0120:06 + +cartridge sha256:5e5cac64fdcf09a52a9c0ab1ebc8bd309dcb1256faf1405284443569b5284fe5 + title:Inindo - Way of the Ninja (USA) + cheat + description:Max defend + code:7EF0C8:FF + cheat + description:Max intelligence + code:7EF0C3:FF + cheat + description:Max luck + code:7EF0C5:FF + cheat + description:Max power + code:7EF0CA:FF + cheat + description:Max resist + code:7EF0C9:FF + cheat + description:Max speed + code:7EF0C4:FF + cheat + description:Start with 50,000 gold + code:A0ED-D460 + cheat + description:Start with 250 health after the first battle + code:ECEC-DFD0 + cheat + description:Start with 100 energy after the first level up + code:10EC-D4D0 + cheat + description:Infinite HP in battle + code:7E9606:E7+7E9607:03 + cheat + description:Max HP + code:7EF0B6:E7+7EF0B7:03 + cheat + description:Infinite energy + code:7EF0BC:E7+7EF0BD:03 + cheat + description:Max energy + code:7EF0BA:E7+7EF0BB:03 + cheat + description:Infinite chips + code:7EF076:FF+7EF077:FF + +cartridge sha256:c7b1706a0ee96f3e0d65cd043c05966bfe3d5c57d08bbd2df3118817424adf82 + title:Inspector Gadget (USA) + cheat + description:Invincibility (keep coat in collisions) + code:C269-5D0D + cheat + description:Infinite time + code:C297-8F0F + cheat + description:Infinite lives + code:C216-5DD4 + cheat + description:Start with 3 plungers + code:D74B-E7D7 + +cartridge sha256:8e0d620a307a225a757bbc9ef2a2a666792e5d533aa0279d3c0060a1b93ead82 + title:Iron Commando - Koutetsu no Senshi (Japan) + cheat + description:Invincibility - Bicycle stages + code:18EA-CDA1 + cheat + description:Infinite ammo + code:C2A1-4D61 + cheat + description:One hit kills (most enemies) + code:40EF-4461+B3C9-4406+BAC9-47D6 + +cartridge sha256:39bfe828571cdb23e7c85c23cf5b175979dcc2042c5841add58f5ae6492168a9 + title:Itchy & Scratchy Game, The (USA) + cheat + description:Infinite health + code:C2E1-402E + cheat + description:Infinite lives + code:C2BB-CDD4 + cheat + description:Infinite time + code:C28A-CD55 + cheat + description:Infinite Bones + code:C28A-3DDF + cheat + description:Infinite health - P1 + code:7E022B:46 + cheat + description:Infinite lives (alt) + code:7E023A:03 + cheat + description:Infinite Cheese speed boost + code:7E023B:03 + cheat + description:Infinite Boss weapons + code:7E023C:0F + +cartridge sha256:183af7d642b55d52cd594786ec2f031d033cc6c8c1a2a84a834e4ada04301b26 + title:Izzy's Quest for the Olympic Rings (USA) + cheat + description:Infinite health (disable then enable when bored in sub games) + code:7E9EB0:03 + cheat + description:Infinite lives + code:7E9E90:0A + cheat + description:Start on Greek Village I + code:7E0394:05+7E0398:05 + cheat + description:Start on Rocket Ride I + code:7E0394:06+7E0398:06 + cheat + description:Start on Greek Village II + code:7E0394:07+7E0398:07 + cheat + description:Start on Space Walk I + code:7E0394:08+7E0398:08 + cheat + description:Start on Greek Village III + code:7E0394:09+7E0398:09 + cheat + description:Start on Rocket Ride II + code:7E0394:0A+7E0398:0A + cheat + description:Start on Lava Dome I + code:7E0394:0B+7E0398:0B + cheat + description:Start on Space Walk II + code:7E0394:0C+7E0398:0C + cheat + description:Start on Lava Dome II + code:7E0394:0D+7E0398:0D + cheat + description:Start on Rocket Ride III + code:7E0394:0E+7E0398:0E + cheat + description:Start on Lava Dome III + code:7E0394:0F+7E0398:0F + cheat + description:Start on Space Walk III + code:7E0394:10+7E0398:10 + cheat + description:Start on Exit to Atlanta I + code:7E0394:11+7E0398:11 + cheat + description:Start on Exit to Atlanta II + code:7E0394:12+7E0398:12 + cheat + description:Start on Round Ends + code:7E0394:13+7E0398:13 + cheat + description:Start on Game Ending + code:7E0394:14+7E0398:14 + +cartridge sha256:62557ee2a3fc3b5a3f59431f966eb61bb380ba983ef6c7742cb55cf075f15f6c + title:J.R.R. Tolkien's The Lord of the Rings - Volume 1 (USA) + cheat + description:Invincibility - all characters + code:82A2-CF6D + cheat + description:Start with 908 HP + code:DBCE-C360+DBCE-C4A0 + cheat + description:Start with 9908 HP + code:BBCE-C360+BBCE-C4A0 + cheat + description:Start the game with more strength + code:62CD-34D0 + cheat + description:9999 HP - character 1 + code:7E0224:99+7E0225:99 + cheat + description:9999 max HP - character 1 + code:7E0236:99+7E0237:99 + cheat + description:9999 EXP - character 1 + code:7E0246:99+7E0247:99 + cheat + description:Level 98 - character 1 + code:7E0256:98 + cheat + description:9999 HP - character 2 + code:7E0226:99+7E0227:99 + cheat + description:9999 max HP - character 2 + code:7E0238:99+7E0239:99 + cheat + description:9999 EXP - character 2 + code:7E0248:99+7E0249:99 + cheat + description:Level 98 - character 2 + code:7E0258:98 + cheat + description:Have all items + code:7E02B0:FF+7E02B1:FF+7E02B2:FF+7E02B3:FF+7E02B4:FF+7E02B5:01+7E02AA:FF+7E02AB:FF+7E02AC:FF+7E02AD:FF+7E02AE:FF+7E02AF:FF + +cartridge sha256:3ffbb6e0ccf8e9f5e4c72d9fe526a16371e562b71a91d6430e562bf358a5126b + title:Jack Nicklaus Golf (USA) + cheat + description:Infinite mulligans + code:82BF-6707 + cheat + description:Mulligan can be taken after any stroke + code:6DB2-0D07 + cheat + description:No mulligans allowed + code:DDBA-0467 + cheat + description:Each round ends after hole 1 + code:DF33-076F+DDEB-D40A + cheat + description:Each round ends after hole 2 + code:D433-076F+DFEB-D40A + cheat + description:Each round ends after hole 3 + code:D733-076F+D4EB-D40A + cheat + description:Each round ends after hole 4 + code:D033-076F+D7EB-D40A + cheat + description:Each round ends after hole 5 + code:D933-076F+D0EB-D40A + cheat + description:Each round ends after hole 6 + code:D133-076F+D9EB-D40A + cheat + description:Each round ends after hole 7 + code:D533-076F+D1EB-D40A + cheat + description:Each round ends after hole 8 + code:D633-076F+D5EB-D40A + cheat + description:Each round ends after hole 9 + code:DB33-076F+D6EB-D40A + cheat + description:Each round ends after hole 10 + code:DC33-076F+DBEB-D40A + cheat + description:Each round ends after hole 11 + code:D833-076F+DCEB-D40A + cheat + description:Each round ends after hole 12 + code:DA33-076F+D8EB-D40A + cheat + description:Each round ends after hole 13 + code:D233-076F+DAEB-D40A + cheat + description:Each round ends after hole 14 + code:D333-076F+D2EB-D40A + cheat + description:Each round ends after hole 15 + code:DE33-076F+D3EB-D40A + cheat + description:Each round ends after hole 16 + code:FD33-076F+DEEB-D40A + cheat + description:Each round ends after hole 17 + code:FF33-076F+FDEB-D40A + +cartridge sha256:9cf82dd9a851cdc38bf2afc286c077ff18a0a5d3bb301eba606cc52db62f8965 + title:James Bond Jr (USA) + cheat + description:Infinite health (can still be hurt by some things) + code:CE2B-D4B6 + cheat + description:Infinite Grenades + code:C22A-6FBC + cheat + description:Infinite Darts + code:C227-DDF8 + cheat + description:Infinite lives on the ground + code:C2E0-6F0D + cheat + description:Infinite lives in the air + code:C26C-6F08 + cheat + description:Hearts worth 0 + code:C23D-6FBC + cheat + description:Large red Grenade worth 0 instead of 5 + code:DD34-679C + cheat + description:Large red Grenade worth 10 + code:DC34-679C + cheat + description:Large red Grenade worth 20 + code:F034-679C + cheat + description:Large red Grenade worth 30 + code:F334-679C + cheat + description:Large red Grenade worth 40 + code:4634-679C + cheat + description:Small silver Grenade worth 0 instead of 1 + code:3C3A-ADFC + cheat + description:Start with 1 life on the ground instead of 5 + code:DFA0-670D + cheat + description:Start with 3 lives on the ground + code:D7A0-670D + cheat + description:Start with 7 lives on the ground + code:D5A0-670D + cheat + description:Start with 9 lives on the ground + code:DBA0-670D + cheat + description:Start with 1 life in the air instead of 5 + code:DF68-DDAD + cheat + description:Start with 3 lives in the air + code:D768-DDAD + cheat + description:Start with 7 lives in the air + code:D568-DDAD + cheat + description:Start with 9 lives in the air + code:DB68-DDAD + cheat + description:Start with 0 Grenades and Darts instead of 10 + code:DDE7-6F6D + cheat + description:Start with 5 Grenades and Darts + code:D9E7-6F6D + cheat + description:Start with 25 Grenades and Darts + code:FBE7-6F6D + cheat + description:Start with 50 Grenades and Darts + code:74E7-6F6D + cheat + description:Start with 99 Grenades and Darts + code:17E7-6F6D + cheat + description:Start with 0 Darts instead of 10 + code:DDA9-640D+CEE7-64AD + cheat + description:Start with 5 Darts + code:D9A9-640D+CEE7-64AD + cheat + description:Start with 25 Darts + code:FBA9-640D+CEE7-64AD + cheat + description:Start with 50 Darts + code:74A9-640D+CEE7-64AD + cheat + description:Start with 99 Darts + code:17A9-640D+CEE7-64AD + cheat + description:Start on level 3 + code:CBAC-6D0D+DFAC-6D6D + cheat + description:Start on level 5 + code:CBAC-6D0D+D4AC-6D6D + cheat + description:Start on level 7 + code:CBAC-6D0D+D7AC-6D6D + cheat + description:Start on level 3, part 2 + code:CBAB-67AD+D0AC-6DDD+6DAC-6D0D + cheat + description:Start on level 3, part 3 + code:CBAB-67AD+D5AC-6DDD+6DAC-6D0D + cheat + description:Start on level 5, part 2 + code:CBAB-67AD+D9AC-6DDD+6DAC-6D0D + cheat + description:Start on level 5, part 3 + code:CBAB-67AD+D6AC-6DDD+6DAC-6D0D + cheat + description:Start on level 7, part 2 + code:CBAB-67AD+D1AC-6DDD+6DAC-6D0D + cheat + description:Start on level 7, part 3 + code:CBAB-67AD+DBAC-6DDD+6DAC-6D0D + +cartridge sha256:f5e74f09c485d58b444ef2b168d041a1d451056b5feb295901974ca73190dbdb + title:Jelly Boy (Europe) + cheat + description:Infinite lives + code:C228-3FD4 + cheat + description:Infinite time + code:C2E3-1D05 + cheat + description:Don't lose Music Notes when hit (can get stuck) + code:C226-4FA7 + +cartridge sha256:bc09f97cb988f6e445fc92e438fff4bf97aa56cb7bbecaa234ffe93bb285d915 + title:Jelly Boy 2 (Japan) (Proto) + cheat + description:Invincibility + code:7E026B:03 + cheat + description:Infinite lives + code:7E0269:03 + +cartridge sha256:ee7a29eb9c302ea2bb235ef990fd8344a6beb9817499941c40a8a94ad5f7c964 + title:Jetsons, The - Invasion of the Planet Pirates (USA) + cheat + description:Invincibility + code:3C62-1761 + cheat + description:Infinite lives + code:C26D-4767 + cheat + description:Infinite time + code:C2AD-4D6F + cheat + description:Maximum vacuum power + code:D0BB-146D + +cartridge sha256:6a2f280ed1ef5166d95e3b0eb1a6665564f7ddcfd3feaf53344a1268b54b85c6 + title:Jikkyou Oshaberi Parodius (Japan) + cheat + description:Infinite lives + code:7E00AC:04 + +cartridge sha256:a314583b11d594b8245b5177aa64a4d3b7497d096edabbea7c1842c57aa2ad2b + title:Jim Lee's WildC.A.T.S - Covert Action Teams (USA) + cheat + description:Invincibility + code:C2C5-CDCB + cheat + description:Infinite health + code:826C-C7C6 + cheat + description:Infinite lives + code:3CB7-1F1C + cheat + description:Infinite health (alt) + code:7E401E:48 + cheat + description:Infinite lives (alt) + code:7E1F93:03 + cheat + description:Infinite bombs + code:7E1F95:09 + +cartridge sha256:6f0bec87ece503b0fbe108cd159ed6f5fa7711b1c4fe31e982af41ad5c638093 + title:Jim Power - The Lost Dimension in 3D (USA) + cheat + description:Invincibility + code:CEAB-1D0D + cheat + description:Infinite lives + code:C9AD-CF0D + cheat + description:Infinite time + code:C920-3FA5 + cheat + description:Infinite SB + code:C93F-4764 + cheat + description:Invincibility (alt) + code:7E074E:39 + cheat + description:Infinite lives (alt) + code:7E003F:09 + cheat + description:Infinite time (alt) + code:7E0043:FF + cheat + description:Infinite SB (alt) + code:7E0041:09 + cheat + description:Jump as high as you want and jump through walls (disable to come back down) + code:7E077E:10 + +cartridge sha256:3b2b8b813b58049a4a86ce1c42d2a651f19fd9bbab2407a494e20cf343d3c1a4 + title:Joe & Mac (USA) + cheat + description:Invincibility after one hit + code:892C-64D4 + cheat + description:Infinite health + code:2BBA-64D7 + cheat + description:Infinite health (alt) + code:8BBA-64D7 + cheat + description:Infinite lives + code:DD36-D40D + cheat + description:Infinite lives (alt) + code:8936-D46D + cheat + description:Infinite Keys + code:C936-D708 + cheat + description:All food fully restores health + code:DDE0-0F6F + cheat + description:Start with 2 lives + code:CBC8-6404+DFC8-6464 + cheat + description:Start with 6 lives + code:CBC8-6404+D9C8-6464 + cheat + description:Start with 10 lives + code:CBC8-6404+DBC8-6464 + cheat + description:Infinite health - P1 + code:7E081C:14 + cheat + description:Infinite health - P2 + code:7E085C:0F + cheat + description:Infinite lives - P1 + code:7E0822:05 + cheat + description:Infinite lives - P2 + code:7E0862:05 + cheat + description:Have no weapon - P1 + code:7E081A:B8 + cheat + description:Have no weapon - P2 + code:7E085A:B8 + cheat + description:Have Bone - P1 + code:7E081A:B9 + cheat + description:Have Bone - P2 + code:7E085A:B9 + cheat + description:Have Boomerang - P1 + code:7E081A:BA + cheat + description:Have Boomerang - P2 + code:7E085A:BA + cheat + description:Have Fire - P1 + code:7E081A:BB + cheat + description:Have Fire - P2 + code:7E085A:BB + cheat + description:Have Wheel - P1 + code:7E081A:BC + cheat + description:Have Wheel - P2 + code:7E085A:BC + +cartridge sha256:38451dcbbcd7069ba232e704dcb747a1438bab0a9508218611a027a7f8dfd547 + title:Joe & Mac 2 - Lost in the Tropics (USA) (Beta) + cheat + description:Infinite health + code:B982-176D + cheat + description:Infinite lives + code:893D-3FAD + cheat + description:Start with $2020 + code:A73B-370D + +cartridge sha256:c9889799a9ae8558f26d66ae546db930c99acb78d921b4395afbbc38da6272aa + title:Joe & Mac 2 - Lost in the Tropics (USA) + cheat + description:Infinite health + code:B987-CD6D + cheat + description:Infinite lives + code:B9C1-3467 + cheat + description:Start with $2020 + code:A73F-47AF + +cartridge sha256:5a76347672ea7d27bb334b1e30bbc73e06f92373883bed499245377327a8f0cf + title:John Madden Football (USA) + cheat + description:Always 1st down + code:C2AB-64A4 + cheat + description:Infinite time-outs + code:3C24-A70D + cheat + description:Play clock is 20 seconds instead of 45 + code:F0A2-A4DD + cheat + description:Play clock is 30 seconds + code:F3A2-A4DD + cheat + description:Play clock is 60 seconds (CPU will run down the play clock) + code:7AA2-A4DD + cheat + description:Play clock is 90 seconds (CPU will run down the play clock) + code:9CA2-A4DD + cheat + description:Only have 3 plays to get a first down or TD (down counter starts at 2) + code:D4A3-6D04 + cheat + description:Only have 2 plays to get a first down or TD (down counter starts at 3) + code:D7A3-6D04 + cheat + description:Only have 1 play to get a first down or TD (down counter starts at 4) + code:D0A3-6D04 + cheat + description:No time-outs instead of 3 - P1 + code:DD69-A407 + cheat + description:6 time-outs - P1 + code:D169-A407 + cheat + description:9 time-outs - P1 + code:DB69-A407 + cheat + description:No time-outs - P2 + code:DD69-A467 + cheat + description:6 time-outs - P2 + code:D169-A467 + cheat + description:9 time-outs - P2 + code:DB69-A467 + cheat + description:Safeties worth 1 point instead of 2 + code:82A6-AF64 + cheat + description:Safeties worth 0 points + code:82A6-AF64+82A6-A404 + cheat + description:Touchdowns worth 0 points instead of 6 + code:DDA4-0767 + cheat + description:Touchdowns worth 1 point + code:DFA4-0767 + cheat + description:Touchdowns worth 2 points + code:D4A4-0767 + cheat + description:Touchdowns worth 3 points + code:D7A4-0767 + cheat + description:Touchdowns worth 4 points + code:D0A4-0767 + cheat + description:Touchdowns worth 5 points + code:D9A4-0767 + cheat + description:Touchdowns worth 7 points + code:D5A4-0767 + cheat + description:Touchdowns worth 8 points + code:D6A4-0767 + cheat + description:Touchdowns worth 9 points + code:DBA4-0767 + cheat + description:Extra points and field goals worth 0 + code:3CA7-A707+3CA7-A767 + cheat + description:Extra point or field goal resets score to 0 + code:B3A7-A7A7 + cheat + description:Start with 3 points - P1 + code:CB6C-6D07+626C-6FD7+416C-6F07+ED6C-6467+D76C-6D67 + cheat + description:Start with 5 points - P1 + code:CB6C-6D07+626C-6FD7+416C-6F07+ED6C-6467 + cheat + description:Start with 9 points - P1 + code:CB6C-6D07+626C-6FD7+416C-6F07+ED6C-6467+DB6C-6D67 + cheat + description:Start with 12 points - P1 + code:CB6C-6D07+626C-6FD7+416C-6F07+ED6C-6467+DA6C-6D67 + cheat + description:Start with 15 points - P1 + code:CB6C-6D07+626C-6FD7+416C-6F07+ED6C-6467+DE6C-6D67 + cheat + description:Start with 20 points - P1 + code:CB6C-6D07+626C-6FD7+416C-6F07+ED6C-6467+F06C-6D67 + cheat + description:Start with 3 points - P2 + code:CB6C-6D07+626C-6FD7+486C-6F07+ED6C-6467+D76C-6D67 + cheat + description:Start with 5 points - P2 + code:CB6C-6D07+626C-6FD7+486C-6F07+ED6C-6467 + cheat + description:Start with 9 points - P2 + code:CB6C-6D07+626C-6FD7+486C-6F07+ED6C-6467+DB6C-6D67 + cheat + description:Start with 12 points - P2 + code:CB6C-6D07+626C-6FD7+486C-6F07+ED6C-6467+DA6C-6D67 + cheat + description:Start with 15 points - P2 + code:CB6C-6D07+626C-6FD7+486C-6F07+ED6C-6467+DE6C-6D67 + cheat + description:Start with 20 points - P2 + code:CB6C-6D07+626C-6FD7+486C-6F07+ED6C-6467+F06C-6D67 + +cartridge sha256:3e62872bf69ea90dd7093608268f8defa2c6016adb1011745dab3c2af45d69b7 + title:John Madden Football '93 (USA) + cheat + description:Infinite timeouts - both players + code:3C3A-0FAD + cheat + description:9 timeouts - P1 + code:DB30-D43A + cheat + description:6 timeouts - P1 + code:D130-D43A + cheat + description:1 timeout - P1 + code:DF30-D43A + cheat + description:9 timeouts - P2 + code:DB30-D74A + cheat + description:6 timeouts - P2 + code:D130-D74A + cheat + description:1 timeout - P2 + code:DF30-D74A + +cartridge sha256:67fa7115eb6bf292c024c3a8b06ce9bd457c4d46de182a06a573afff968cc0f1 + title:Judge Dredd (USA) + cheat + description:Invincible after first hit + code:C22C-1B2D + cheat + description:Almost infinite health + code:C2A9-1627 + cheat + description:Almost infinite ammo + code:C2BE-4A4B + cheat + description:Don't flash after getting hit + code:DDA9-1CB7 + cheat + description:Don't flash as long after getting hit + code:74A9-1CB7 + cheat + description:Flash longer after getting hit + code:EEA9-1CB7 + cheat + description:Start with all weapons and almost infinite ammo + code:EE63-1318 + cheat + description:Start with very little energy on your first life + code:DE6D-C338 + cheat + description:Start with half energy on your first life + code:6D6D-C338 + cheat + description:Start with about 3/4 energy on your first life + code:A16D-C338 + cheat + description:Start with very little energy after first life + code:DE3A-48B7 + cheat + description:Start with half energy after first life + code:6D3A-48B7 + cheat + description:Start with about 3/4 energy after first life + code:A13A-48B7 + cheat + description:Start with 1 life + code:DF62-1A38 + cheat + description:Start with 5 lives + code:D962-1A38 + cheat + description:Start with 9 lives + code:DB62-1A38 + cheat + description:Invincibility + code:7E1A91:01 + cheat + description:Infinite health + code:7E1B11:FF + cheat + description:Infinite lives + code:7E1AF7:09 + cheat + description:Infinte Grenades + code:7E1B01:99 + cheat + description:Infinite Boing + code:7E1B0D:99 + cheat + description:Infinite Richochet + code:7E1AFF:99 + cheat + description:Infinite Seeker + code:7E1B09:99 + cheat + description:Infinite Double Whammie + code:7E1B0B:99 + cheat + description:Infinite Incindiary + code:7E1B05:99 + cheat + description:Infinte High Explosive + code:7E1B03:99 + cheat + description:Infinte Armor Piercing + code:7E1B07:99 + cheat + description:Infinite Flare + code:7E1B0F:99 + cheat + description:Infinite Hover Board and Hover Boots + code:7E1AA5:F9 + +cartridge sha256:02cb423199be3368fc2b40148f83b7a48900394983e04d43f94bb7d76ce44e94 + title:Judge Dredd (Europe) + cheat + description:Invincibility + code:7E1A91:01 + cheat + description:Infinite health + code:7E1B11:FF + cheat + description:Infinite lives + code:7E1AF7:09 + cheat + description:Infinte Grenades + code:7E1B01:99 + cheat + description:Infinite Boing + code:7E1B0D:99 + cheat + description:Infinite Richochet + code:7E1AFF:99 + cheat + description:Infinite Seeker + code:7E1B09:99 + cheat + description:Infinite Double Whammie + code:7E1B0B:99 + cheat + description:Infinite Incindiary + code:7E1B05:99 + cheat + description:Infinte High Explosive + code:7E1B03:99 + cheat + description:Infinte Armor Piercing + code:7E1B07:99 + cheat + description:Infinite Flare + code:7E1B0F:99 + cheat + description:Infinite Hover Board and Hover Boots + code:7E1AA5:F9 + +cartridge sha256:771a0322d9f5f8e13a52d01e80257a1f75cc693cf4abf74793520eb5f8b5580e + title:Jungle Book, The (USA) + cheat + description:Infinite weapons + code:DD6F-4DD4 + cheat + description:Infinite lives + code:C2CC-4704 + cheat + description:Hearts from big jungle fruit restore all energy + code:DDCF-3F6D + cheat + description:Super-jump - Mowgli + code:E8CA-3DA4 + cheat + description:Mega-jump - Mowgli + code:ECCA-3DA4 + cheat + description:20 seconds from hourglass + code:D4C0-1FAF + cheat + description:30 seconds from hourglass + code:D7C0-1FAF + cheat + description:Bonus gems worth 2 (don't collect over 100) + code:D4CA-4DDF + cheat + description:Bonus gems worth 3 (don't collect over 100) + code:D7CA-4DDF + cheat + description:Bonus gems worth 4 (don't collect over 100) + code:D0CA-4DDF + cheat + description:Red gems worth 2 (don't collect over 100) + code:D4C2-4FAF + cheat + description:Red gems worth 3 (don't collect over 100) + code:D7C2-4FAF + cheat + description:Red gems worth 4 (don't collect over 100) + code:D0C2-4FAF + cheat + description:The amazing rock (just for fun) + code:DD65-47AD + cheat + description:Start with 9 hearts (normal game) + code:DBEF-1F67 + cheat + description:Start with 6 hearts (normal game) + code:D1EF-1F67 + cheat + description:Start with 1 heart (normal game) + code:DFEF-1F67 + cheat + description:Start with 10 lives (normal game) + code:DBEF-1DD7 + cheat + description:Start with 2 lives (normal game) + code:DFEF-1DD7 + cheat + description:Invincibility + code:7E068C:31 + cheat + description:Infinite health + code:7E010B:04 + cheat + description:Have 99 green gems + code:7E015D:99 + cheat + description:Have 99 red gems + code:7E015E:99 + +cartridge sha256:8d812ea4fa897274116f7f43bc689e110f1cfbd3f7eb3a1737c2a85d36369159 + title:Jungle Strike (USA) + cheat + description:Infinite ammo + code:C2A5-476F + cheat + description:Infinite armor + code:C2A9-4FA7 + cheat + description:Infinite lives + code:CEBE-C4D4 + cheat + description:Start with less fuel + code:7485-C7D1 + cheat + description:Start with more fuel + code:7485-C7D1 + cheat + description:Start with mega fuel + code:7485-C701 + cheat + description:Start with 0 hellfires + code:DD86-C761 + cheat + description:Start with more hellfires + code:B186-C761 + cheat + description:Start with mega hellfires + code:B186-C7A1 + cheat + description:Start with less gun ammo + code:DD8B-C4A1 + cheat + description:Start with more gun ammo + code:F18B-C4A1 + cheat + description:Start with mega gun ammo + code:748B-C4A1 + cheat + description:Start with less hydras + code:FB8B-CFD1 + cheat + description:Start with more hydras + code:EE8B-CFD1 + cheat + description:Start with mega hydras + code:748B-CF01 + +cartridge sha256:0a4e9d6fa2ac16aa51da5538d93280734de480e44c430173ed14826c84553c7d + title:Jurassic Park (USA) (Rev 1) + cheat + description:Infinite lives + code:C26A-4700 + cheat + description:Cattle Prod energy recharges to about 3/4 full when outside + code:F682-CFAD + cheat + description:Cattle Prod energy recharges to about 1/2 full when outside + code:FD82-CFAD + cheat + description:Cattle Prod energy recharges to about 1/4 full when outside + code:D682-CFAD + cheat + description:Infinite Cattle Prod energy when outside + code:C285-C76D + cheat + description:Infinite 1st weapons when outside + code:C2CB-3407 + cheat + description:Infinite 2nd weapons when outside (except gas grenade) + code:8289-4DAD + cheat + description:Cattle Prod energy recharges to 1/2 full when inside + code:EDEA-4767 + cheat + description:Infinite Cattle Prod energy when inside + code:C282-4B65 + cheat + description:Infinite 1st weapons when inside + code:3CC4-3C65+3CCA-36D5 + cheat + description:Infinite 2nd weapons when inside (except gas grenade) + code:C2C6-3BD1 + cheat + description:Infinite continues with 4 lives + code:C2B8-C4D0 + cheat + description:Continue 1st time with 5 lives + code:D0BC-CDA0 + cheat + description:Continue with 5 lives after 1st continue + code:D0BC-C7D0 + cheat + description:Start with 1 egg needed + code:DF23-3469 + cheat + description:Start with 2 lives + code:DF2E-3DD9 + cheat + description:Start with 4 lives + code:D72E-3DD9 + cheat + description:Infinite health + code:7E02EB:03 + cheat + description:Infinite lives (alt) + code:7E02A3:03 + cheat + description:Infinite ammo - all weapons + code:7E028B:20+7E0295:20+7E029F:20 + cheat + description:Generator on + code:7E00F0:EF + cheat + description:Have level 1 security card + code:7E0265:01 + cheat + description:Have level 2 security card + code:7E0267:01 + cheat + description:Have all 18 Eggs + code:7E0E0F:00+7E0E10:00 + cheat + description:Have John Hammond ID Card + code:7E0253:01 + cheat + description:Have Dr. Ellie Sattler ID Card + code:7E0255:01 + cheat + description:Have Robert Muldoon ID Card + code:7E0257:01 + cheat + description:Have Dr. Allen Grant ID Card + code:7E0259:01 + cheat + description:Have Donald Gennaro ID Card + code:7E025B:01 + cheat + description:Have Ray Arnold ID Card + code:7E025E:01 + cheat + description:Have Dennis Nedry ID Card + code:7E0260:01 + cheat + description:Have Dr. Henry Wu ID Card + code:7E0261:01 + cheat + description:Have Dr. Ian Malcolm ID Card + code:7E0263:01 + +cartridge sha256:fe91d45201753ae9655d5ce38838e352f478b26b2d933c1bcb5bd8330121f9ff + title:Jurassic Park (USA) + cheat + description:Infinite lives + code:C26A-4700 + cheat + description:Cattle Prod energy recharges to about 3/4 full when outside + code:F682-CFAD + cheat + description:Cattle Prod energy recharges to about 1/2 full when outside + code:FD82-CFAD + cheat + description:Cattle Prod energy recharges to about 1/4 full when outside + code:D682-CFAD + cheat + description:Infinite Cattle Prod energy when outside + code:C285-C76D + cheat + description:Infinite 1st weapons when outside + code:C2CB-3407 + cheat + description:Infinite 2nd weapons when outside (except gas grenade) + code:8289-4DAD + cheat + description:Cattle Prod energy recharges to 1/2 full when inside + code:EDEA-4767 + cheat + description:Infinite Cattle Prod energy when inside + code:C282-4B65 + cheat + description:Infinite 1st weapons when inside + code:3CC4-3C65+3CCA-36D5 + cheat + description:Infinite 2nd weapons when inside (except gas grenade) + code:C2C6-3BD1 + cheat + description:Infinite continues with 4 lives + code:C2B8-C4D0 + cheat + description:Continue 1st time with 5 lives + code:D0BC-CDA0 + cheat + description:Continue with 5 lives after 1st continue + code:D0BC-C7D0 + cheat + description:Start with 1 egg needed + code:DF23-3469 + cheat + description:Start with 2 lives + code:DF2E-3DD9 + cheat + description:Start with 4 lives + code:D72E-3DD9 + cheat + description:Infinite health + code:7E02EB:03 + cheat + description:Infinite lives (alt) + code:7E02A3:03 + cheat + description:Infinite ammo - all weapons + code:7E028B:20+7E0295:20+7E029F:20 + cheat + description:Generator on + code:7E00F0:EF + cheat + description:Have level 1 security card + code:7E0265:01 + cheat + description:Have level 2 security card + code:7E0267:01 + cheat + description:Have all 18 Eggs + code:7E0E0F:00+7E0E10:00 + cheat + description:Have John Hammond ID Card + code:7E0253:01 + cheat + description:Have Dr. Ellie Sattler ID Card + code:7E0255:01 + cheat + description:Have Robert Muldoon ID Card + code:7E0257:01 + cheat + description:Have Dr. Allen Grant ID Card + code:7E0259:01 + cheat + description:Have Donald Gennaro ID Card + code:7E025B:01 + cheat + description:Have Ray Arnold ID Card + code:7E025E:01 + cheat + description:Have Dennis Nedry ID Card + code:7E0260:01 + cheat + description:Have Dr. Henry Wu ID Card + code:7E0261:01 + cheat + description:Have Dr. Ian Malcolm ID Card + code:7E0263:01 + +cartridge sha256:5eff7c27f69b3ebc1ec1294ffcd1debf3512bc3e6c1c75fbdc5e778dcaaba1c9 + title:Jurassic Park II - The Chaos Continues (USA) (En,Fr,De,It) + cheat + description:Almost invincible + code:8BEB-C22D+8B65-1C67 + cheat + description:Invincibiltiy after one hit until you enter a new screen + code:82B6-C704 + cheat + description:Infintie health against some larger dinosaurs + code:6DED-3A9D + cheat + description:One hit kills on some dinosaurs + code:D462-48DD + cheat + description:Regular Gun is super strong + code:0D6A-106E + cheat + description:Flash longer after getting hit + code:EE30-1DAF + cheat + description:Don't flash after getting hit + code:DD30-1DAF + cheat + description:Velociraptor takes more damage + code:4DC5-C67C + cheat + description:Start with less Machine Gun ammo + code:DEC0-397D + cheat + description:Start with more Shotgun ammo + code:10C0-31ED + cheat + description:Start with less Tranquilizer Gun ammo + code:FDC9-315D + cheat + description:Start with more Tranquilizer Missiles + code:10C1-307D + cheat + description:Invincibility - P1 + code:7EB04A:0E + cheat + description:Infinite health - P1 + code:7EB032:28 + cheat + description:Infinite Machine Gun ammo + code:7EA9B0:FF + cheat + description:Infinite Shotgun ammo + code:7EA9B2:FF + cheat + description:Infinite Grenade Launcher + code:7EA9B6:FF + cheat + description:Infinite Dino stock + code:7E0008:64 + cheat + description:Have Rifle + code:7EB040:00 + cheat + description:Have Machine Gun + code:7EB040:01 + cheat + description:Have Shotgun + code:7EB040:02 + cheat + description:Have Charge Gun + code:7EB040:03 + cheat + description:Have Tranquilizer Gun + code:7EB040:04 + cheat + description:Have Big Bomb Gun + code:7EB040:05 + cheat + description:Have Big Bomb Gun with Dinosaur icon + code:7EB040:07 + cheat + description:Have Needle Gun with clock icon + code:7EB040:08 + +cartridge sha256:7f05959f423bc656091ea3bddfbc89c877ae243dca346f63233e27973f34e0eb + title:Justice League Task Force (USA) + cheat + description:Infinite health - P1 + code:7E0CF7:60 + cheat + description:No health - P2 + code:7E0CF9:00 + cheat + description:Infinite time + code:7E0335:99 + cheat + description:Win match after one round + code:7E0547:02+7E0EFB:02 + +cartridge sha256:05152bcf9bf086e7bcdbfa7dd8edfe2085f1339c4d7e193e0071c49a10471ef4 + title:Kablooey (USA) + cheat + description:Infinite lives + code:C261-0F0D + cheat + description:Bonus timer doesn't count down + code:3C27-6D0D + cheat + description:Level is completed after only one bomb goes off + code:BAC8-07D4 + cheat + description:Start with 1 life instead of 5 + code:DF6B-D76D + cheat + description:Start with 3 lives + code:D76B-D76D + cheat + description:Start with 10 lives + code:DC6B-D76D + cheat + description:Start with 25 lives + code:FB6B-D76D + cheat + description:Start with 50 lives + code:746B-D76D + cheat + description:Start with 75 lives + code:086B-D76D + cheat + description:Start with 98 lives + code:146B-D76D + cheat + description:Start on level 2 + code:BA25-07D7+DF25-04D7 + cheat + description:Start on level 3 + code:BA25-07D7+D425-04D7 + cheat + description:Start on level 4 + code:BA25-07D7+D725-04D7 + cheat + description:Start on level 5 + code:BA25-07D7+D025-04D7 + cheat + description:Start on level 6 + code:BA25-07D7+D925-04D7 + cheat + description:Start on level 7 + code:BA25-07D7+D125-04D7 + cheat + description:Start on level 8 + code:BA25-07D7+D525-04D7 + cheat + description:Start on level 9 + code:BA25-07D7+D625-04D7 + cheat + description:Start on level 10 + code:BA25-07D7+DB25-04D7 + cheat + description:Start on level 11 + code:BA25-07D7+DC25-04D7 + cheat + description:Start on level 12 + code:BA25-07D7+D825-04D7 + cheat + description:Start on level 13 + code:BA25-07D7+DA25-04D7 + cheat + description:Start on level 14 + code:BA25-07D7+D225-04D7 + cheat + description:Start on level 15 + code:BA25-07D7+D325-04D7 + cheat + description:Start on level 16 + code:BA25-07D7+DE25-04D7 + cheat + description:Start on level 17 + code:BA25-07D7+FD25-04D7 + cheat + description:Start on level 18 + code:BA25-07D7+FF25-04D7 + cheat + description:Start on level 19 + code:BA25-07D7+F425-04D7 + cheat + description:Start on level 20 + code:BA25-07D7+F725-04D7 + cheat + description:Start on level 21 + code:BA25-07D7+F025-04D7 + cheat + description:Start on level 22 + code:BA25-07D7+F925-04D7 + cheat + description:Start on level 23 + code:BA25-07D7+F125-04D7 + cheat + description:Start on level 24 + code:BA25-07D7+F525-04D7 + cheat + description:Start on level 25 + code:BA25-07D7+F625-04D7 + cheat + description:Start on level 26 + code:BA25-07D7+FB25-04D7 + cheat + description:Start on level 27 + code:BA25-07D7+FC25-04D7 + cheat + description:Start on level 28 + code:BA25-07D7+F825-04D7 + cheat + description:Start on level 29 + code:BA25-07D7+FA25-04D7 + cheat + description:Start on level 30 + code:BA25-07D7+F225-04D7 + cheat + description:Start on level 31 + code:BA25-07D7+F325-04D7 + cheat + description:Start on level 32 + code:BA25-07D7+FE25-04D7 + cheat + description:Start on level 33 + code:BA25-07D7+4D25-04D7 + cheat + description:Start on level 34 + code:BA25-07D7+4F25-04D7 + cheat + description:Start on level 35 + code:BA25-07D7+4425-04D7 + cheat + description:Start on level 36 + code:BA25-07D7+4725-04D7 + cheat + description:Start on level 37 + code:BA25-07D7+4025-04D7 + cheat + description:Start on level 38 + code:BA25-07D7+4925-04D7 + cheat + description:Start on level 39 + code:BA25-07D7+4125-04D7 + cheat + description:Start on level 40 + code:BA25-07D7+4525-04D7 + cheat + description:Start on level 41 + code:BA25-07D7+4625-04D7 + cheat + description:Start on level 42 + code:BA25-07D7+4B25-04D7 + cheat + description:Start on level 43 + code:BA25-07D7+4C25-04D7 + cheat + description:Start on level 44 + code:BA25-07D7+4825-04D7 + cheat + description:Start on level 45 + code:BA25-07D7+4A25-04D7 + cheat + description:Start on level 46 + code:BA25-07D7+4225-04D7 + cheat + description:Start on level 47 + code:BA25-07D7+4325-04D7 + cheat + description:Start on level 48 + code:BA25-07D7+4E25-04D7 + cheat + description:Start on level 49 + code:BA25-07D7+7D25-04D7 + cheat + description:Start on level 50 + code:BA25-07D7+7F25-04D7 + cheat + description:Start on level 51 + code:BA25-07D7+7425-04D7 + cheat + description:Start on level 52 + code:BA25-07D7+7725-04D7 + cheat + description:Start on level 53 + code:BA25-07D7+7025-04D7 + cheat + description:Start on level 54 + code:BA25-07D7+7925-04D7 + cheat + description:Start on level 55 + code:BA25-07D7+7125-04D7 + cheat + description:Start on level 56 + code:BA25-07D7+7525-04D7 + cheat + description:Start on level 57 + code:BA25-07D7+7625-04D7 + cheat + description:Start on level 58 + code:BA25-07D7+7B25-04D7 + cheat + description:Start on level 59 + code:BA25-07D7+7C25-04D7 + cheat + description:Start on level 60 + code:BA25-07D7+7825-04D7 + cheat + description:Start on level 61 + code:BA25-07D7+7A25-04D7 + cheat + description:Start on level 62 + code:BA25-07D7+7225-04D7 + cheat + description:Start on level 63 + code:BA25-07D7+7325-04D7 + cheat + description:Start on level 64 + code:BA25-07D7+7E25-04D7 + cheat + description:Start on level 65 + code:BA25-07D7+0D25-04D7 + cheat + description:Start on level 66 + code:BA25-07D7+0F25-04D7 + cheat + description:Start on level 67 + code:BA25-07D7+0425-04D7 + cheat + description:Start on level 68 + code:BA25-07D7+0725-04D7 + cheat + description:Start on level 69 + code:BA25-07D7+0025-04D7 + cheat + description:Start on level 70 + code:BA25-07D7+0925-04D7 + cheat + description:Start on level 71 + code:BA25-07D7+0125-04D7 + cheat + description:Start on level 72 + code:BA25-07D7+0525-04D7 + cheat + description:Start on level 73 + code:BA25-07D7+0625-04D7 + cheat + description:Start on level 74 + code:BA25-07D7+0B25-04D7 + cheat + description:Start on level 75 + code:BA25-07D7+0C25-04D7 + cheat + description:Start on level 76 + code:BA25-07D7+0825-04D7 + cheat + description:Start on level 77 + code:BA25-07D7+0A25-04D7 + cheat + description:Start on level 78 + code:BA25-07D7+0225-04D7 + cheat + description:Start on level 79 + code:BA25-07D7+0325-04D7 + cheat + description:Start on level 80 + code:BA25-07D7+0E25-04D7 + cheat + description:Start on level 81 + code:BA25-07D7+9D25-04D7 + cheat + description:Start on level 82 + code:BA25-07D7+9F25-04D7 + cheat + description:Start on level 83 + code:BA25-07D7+9425-04D7 + cheat + description:Start on level 84 + code:BA25-07D7+9725-04D7 + cheat + description:Start on level 85 + code:BA25-07D7+9025-04D7 + cheat + description:Start on level 86 + code:BA25-07D7+9925-04D7 + cheat + description:Start on level 87 + code:BA25-07D7+9125-04D7 + cheat + description:Start on level 88 + code:BA25-07D7+9525-04D7 + cheat + description:Start on level 89 + code:BA25-07D7+9625-04D7 + cheat + description:Start on level 90 + code:BA25-07D7+9B25-04D7 + cheat + description:Start on level 91 + code:BA25-07D7+9C25-04D7 + cheat + description:Start on level 92 + code:BA25-07D7+9825-04D7 + cheat + description:Start on level 93 + code:BA25-07D7+9A25-04D7 + cheat + description:Start on level 94 + code:BA25-07D7+9225-04D7 + cheat + description:Start on level 95 + code:BA25-07D7+9325-04D7 + cheat + description:Start on level 96 + code:BA25-07D7+9E25-04D7 + cheat + description:Start on level 97 + code:BA25-07D7+1D25-04D7 + cheat + description:Start on level 98 + code:BA25-07D7+1F25-04D7 + cheat + description:Start on level 99 + code:BA25-07D7+1425-04D7 + cheat + description:Start on level 100 + code:BA25-07D7+1725-04D7 + cheat + description:Start on level 101 + code:BA25-07D7+1025-04D7 + cheat + description:Start on level 102 + code:BA25-07D7+1925-04D7 + cheat + description:Start on level 103 + code:BA25-07D7+1125-04D7 + cheat + description:Start on level 104 + code:BA25-07D7+1525-04D7 + cheat + description:Start on level 105 + code:BA25-07D7+1625-04D7 + cheat + description:Start on level 106 + code:BA25-07D7+1B25-04D7 + cheat + description:Start on level 107 + code:BA25-07D7+1C25-04D7 + cheat + description:Start on level 108 + code:BA25-07D7+1825-04D7 + cheat + description:Start on level 109 + code:BA25-07D7+1A25-04D7 + cheat + description:Start on level 110 + code:BA25-07D7+1225-04D7 + cheat + description:Start on level 111 + code:BA25-07D7+1325-04D7 + cheat + description:Start on level 112 + code:BA25-07D7+1E25-04D7 + cheat + description:Start on level 113 + code:BA25-07D7+5D25-04D7 + cheat + description:Start on level 114 + code:BA25-07D7+5F25-04D7 + cheat + description:Start on level 115 + code:BA25-07D7+5425-04D7 + cheat + description:Start on level 116 + code:BA25-07D7+5725-04D7 + cheat + description:Start on level 117 + code:BA25-07D7+5025-04D7 + cheat + description:Start on level 118 + code:BA25-07D7+5925-04D7 + cheat + description:Start on level 119 + code:BA25-07D7+5125-04D7 + cheat + description:Start on level 120 + code:BA25-07D7+5525-04D7 + cheat + description:Start on level 121 + code:BA25-07D7+5625-04D7 + cheat + description:Start on level 122 + code:BA25-07D7+5B25-04D7 + cheat + description:Start on level 123 + code:BA25-07D7+5C25-04D7 + cheat + description:Start on level 124 + code:BA25-07D7+5825-04D7 + cheat + description:Start on level 125 + code:BA25-07D7+5A25-04D7 + cheat + description:Start on level 126 + code:BA25-07D7+5225-04D7 + cheat + description:Start on level 127 + code:BA25-07D7+5325-04D7 + cheat + description:Start on level 128 + code:BA25-07D7+5E25-04D7 + cheat + description:Start on level 129 + code:BA25-07D7+6D25-04D7 + cheat + description:Start on level 130 + code:BA25-07D7+6F25-04D7 + +cartridge sha256:6f2dc2486d680fe557ed6e2e7082480aad6537c6a04845bb6a6b8ef5e3d698ef + title:Kamen Rider (Japan) + cheat + description:Invincibility + code:C268-3DD4 + cheat + description:Infinite health + code:0D68-34D4+6E68-3464+1C68-34A4+DA68-37D4+5368-3704 + cheat + description:Infinite lives + code:A2EF-1FD5 + cheat + description:Infinite health (alt) + code:7E0C6A:40 + cheat + description:Infinite lives (alt) + code:7E0038:02 + +cartridge sha256:f9ec39546e18b15b8f6a738204d0227c1542cd8157e3e0ea16934e76f39e288c + title:Karura Ou (Japan) + cheat + description:Invincibility + code:7E0065:9E + cheat + description:Infinite health + code:7EF801:04 + cheat + description:Infinite special power + code:7E1F0D:08 + cheat + description:Infinite Warrior Force + code:7E0089:FF + cheat + description:Have 99 gems + code:7E1F0E:63 + cheat + description:Have Aura Attack + code:7E1F0B:01 + cheat + description:Have Comet Flash + code:7E1F0B:02 + cheat + description:Have Lightning Strike + code:7E1F0B:03 + cheat + description:Have Time Stop + code:7E1F0B:04 + cheat + description:Have Star Fire + code:7E1F0B:05 + cheat + description:Have Warrior Force + code:7E1F0B:06 + cheat + description:Have Heal + code:7E1F0B:07 + cheat + description:Have Fiery Phoenix + code:7E1F0B:08 + cheat + description:All enemies frozen + code:7EFA69:8D+7EFA6A:8D+7EFA6B:8D+7EFA73:8D+7EFA6C:8D+7EFA74:8D+7EFA6D:8D+7EFA75:8D+7EFA6E:8D+7EFA7D:8D+7EFA76:8D+7EFA6F:8D+7EFA7E:8D+7EFA77:8D+7EFA70:8D+7EFA7F:8D+7EFA78:8D+7EFA71:8D+7EFA79:8D+7EFA72:8D+7EFA7A:8D+7EFA7B:8D+7EFA7C:8D+7EFA60:8D+7EFA61:8D+7EFA62:8D+7EFA63:8D+7EFA64:8D+7EFA65:8D+7EFA66:8D+7EFA67:8D+7EFA68:8D + +cartridge sha256:7cc3693cc5e1e834d57795f04b048fab27864a898a9507e7ca383771e2035414 + title:Kawasaki Caribbean Challenge (USA) + cheat + description:Only 1 lap required to qualify instead of 2 + code:DF6F-64AD + cheat + description:Races are 1 lap instead of 5 + code:DF67-676D + cheat + description:Races are 2 laps + code:D467-676D + cheat + description:Races are 3 laps + code:D767-676D + cheat + description:Races are 4 laps + code:D067-676D + cheat + description:Coming in first is worth 9 points instead of 5 + code:DB82-0DD7 + cheat + description:Coming in last is worth 5 points instead of 0 + code:D982-0FD7 + cheat + description:Coming in last is worth 9 points + code:DB82-0FD7 + cheat + description:Always advance to the next island regardless of points + code:6D80-DD04 + cheat + description:Each island requires 3 points instead of 5 + code:D7C2-0F04 + cheat + description:Each island requires 4 points + code:D0C2-0F04 + cheat + description:Each island requires 6 points + code:D1C2-0F04 + cheat + description:Each island requires 7 points + code:D5C2-0F04 + cheat + description:Opponents drive erratically - player is guaranteed 1st place + code:6967-07AD + cheat + description:Start the Challenge with the 2nd motorcycle and jet ski + code:6967-070D + +cartridge sha256:3104d6c06c8909c56f6adb2faecf1b4382f2490370798b605631da926c5306d8 + title:Ken Griffey Jr. Presents Major League Baseball (USA) + cheat + description:Can't strike out + code:C2BE-179D + cheat + description:No outs except strike outs + code:C2A2-4D94+C2AA-47B4 + cheat + description:Can't walk a player + code:CBB3-1D2D + cheat + description:Invisible baserunners + code:DF27-CFA4 + cheat + description:2 outs and whole team is out + code:D4C3-170F + cheat + description:1 ball and you walk + code:DFC3-170F + cheat + description:2 balls and you walk + code:D4C3-170F + cheat + description:1 strike and you're out + code:DFCE-1F0F + cheat + description:2 strikes and you're out + code:D4CE-1F0F + cheat + description:Computer can't score + code:C28A-3FA7 + cheat + description:Computer can't score + code:CBB0-4797 + cheat + description:Computer can't score + code:C283-34D7 + +cartridge sha256:b16661d5151d73cea5ac46d7c899531c7b2cdee2558092c23a5460c8092b80b8 + title:Kendo Rage (USA) + cheat + description:Invincibility + code:7E1476:03 + cheat + description:Infinite HP + code:7E148E:40 + cheat + description:Infinite lives + code:7E0CE2:03 + cheat + description:Infinite PSY power + code:7E148A:40 + cheat + description:Have 9 Yellow Balls + code:7E1494:09 + cheat + description:Have Triple Shot + code:7E1492:00 + cheat + description:Have Multi-Attack + code:7E1492:08 + cheat + description:Have Flame Shot + code:7E1492:10 + cheat + description:Start on round 1 - Cliff Hanger + code:7E0CE4:00 + cheat + description:Start on round 2 - Ice Queen + code:7E0CE4:01 + cheat + description:Start on round 3 - The Pond + code:7E0CE4:02 + cheat + description:Start on round 4 - Technodvne + code:7E0CE4:03 + cheat + description:Start on round 5 - The Commute + code:7E0CE4:04 + cheat + description:Start on round 6 - Triathalon + code:7E0CE4:05 + cheat + description:Start on round 7 - School Daze + code:7E0CE4:06 + +cartridge sha256:914652f72d6ceb83b8b43414d6c42581ec12e9b3f45259b8b2768d26b8d4f073 + title:Kid Klown in Crazy Chase (USA) + cheat + description:Infinite health + code:C229-1D67 + cheat + description:Infinite continues + code:C238-1F27 + +cartridge sha256:317e25d731bbfec30bfdc5fbe4ed825cd08613a4d62d98247bae5ec85783074c + title:Kidou Butouden G Gundam (Japan) + cheat + description:Infinite health + code:7E07D4:80 + +cartridge sha256:1b50f8aa5ae75c4b01e237b29b0a1ec1f1f809bdbe76a23d9c204541ccbf403d + title:Kidou Senshi V Gundam (Japan) + cheat + description:Infinite health + code:7E0522:69 + cheat + description:One hit kills + code:7E06A2:00+7E0822:00 + cheat + description:Infinite lives + code:7E0306:63 + +cartridge sha256:a1c04fc26c65a6ae3c3a496410290e7f437d19ac24a930286521ce04c887212a + title:Kidou Soukou Dion (Japan) + cheat + description:Invincibility (blinking) + code:7E0A50:4C + cheat + description:Infinite health + code:7E0B48:05 + cheat + description:Infinite bombs + code:7E0B14:09 + +cartridge sha256:2b27e9bceb646a300566248fcdcbd582435f50bd6132b0f0025cc146a9d62bd9 + title:Kikou Keisatsu Metal Jack (Japan) + cheat + description:Invincibility + code:ED88-A467 + cheat + description:Infinite health + code:C983-A9CF + cheat + description:Infinite lives + code:C9A7-A76D + cheat + description:Infinite health (alt) + code:7E0060:31 + cheat + description:Infinite lives (alt) + code:7E0061:09 + cheat + description:Infinite time + code:7E0031:06+7E0032:00 + cheat + description:Infinite ammo + code:7E006B:63 + cheat + description:Moon-jump + code:7E005F:01 + cheat + description:Moon-jump when attacking + code:7E0072:20 + cheat + description:Can't walk + code:7E006C:03 + +cartridge sha256:7a5261f1a5e84b67483c79fb002ce1539f2360f88333bda60f12e617d86e0def + title:Killer Instinct (USA) (Rev 1) + cheat + description:Invincibility - P1 + code:3DBB-3F07+A7BB-3407+DDBB-3F67+EDBB-34D7 + cheat + description:Hit anywhere - P1 + code:0AB6-3D67+CAB6-3DA7+CFB6-3FD7+D2B6-3D07+EDB6-3DD7 + cheat + description:Infinite health - P1 + code:7E0D24:78+7E0D26:78 + cheat + description:Infinite health - P2 + code:7E0D28:78+7E0D2A:78 + cheat + description:No health - P1 + code:7E0D24:00+7E0D26:00 + cheat + description:No health - P2 + code:7E0D28:00+7E0D2A:00 + cheat + description:CPU cannot move from starting position + code:7E0E08:01 + cheat + description:Play as Eyedol + code:7E024E:0A + +cartridge sha256:618a23636e07110e094277ec1d1e60c3620a6e9a5f386292808267593fa803ad + title:Killer Instinct (USA) + cheat + description:Master code - must be entered + code:3C61-D4DF + cheat + description:Invincibility - P1 + code:3DB6-3467+A7B6-3767+DDB6-34A7+EDB6-3707 + cheat + description:Hit anywhere - P1 + code:0AB5-3FA7+CFB5-3407+CFB5-34D7+D2B5-3F67+EDB5-3F07 + cheat + description:P1 takes all damage + code:EEC1-34AF + cheat + description:Always fight Jago + code:C265-1467+60E6-47D2 + cheat + description:Always fight Combo + code:C265-1467+6EE6-47D2 + cheat + description:Always fight Thunder + code:C265-1467+6BE6-47D2 + cheat + description:Always fight Glacius + code:C265-1467+6FE6-47D2 + cheat + description:Always fight Cinder + code:C265-1467+6DE6-47D2 + cheat + description:Always fight Orchid + code:C265-1467+64E6-47D2 + cheat + description:Always Fight Riptor + code:C265-1467+B0E6-47D2 + cheat + description:Always fight Sabrewulf + code:C265-1467+CBE6-4702 + cheat + description:Always fight Spinal + code:C265-1467+CBEC-4702 + cheat + description:Always fight Fulgore + code:C265-1467+CBE8-4D62 + cheat + description:Always fight Eyedol + code:C265-1467+CBE8-4FA2 + cheat + description:Infinite health - P1 + code:7E0D24:78+7E0D26:78 + cheat + description:Infinite health - P2 + code:7E0D28:78+7E0D2A:78 + cheat + description:No health - P1 + code:7E0D24:00+7E0D26:00 + cheat + description:No health - P2 + code:7E0D28:00+7E0D2A:00 + cheat + description:CPU cannot move from starting position + code:7E0E08:01 + cheat + description:Play as Eyedol + code:7E024E:0A + +cartridge sha256:1b58d0aed4510811c73d267244a7e915aa0b334c86e68f3fa5883f5cb534e4d7 + title:King Arthur & The Knights of Justice (USA) + cheat + description:Infinite health + code:8B6B-14F4 + cheat + description:Infinite attack power + code:33BD-14AF+33B9-176F + cheat + description:Infinite healing herbs + code:C28A-4DAC + cheat + description:Start with 99 healing herbs + code:14E6-37D4 + cheat + description:Start with 99 shield attacks + code:14EB-3764 + +cartridge sha256:aca9eb59d6783e2cae3787c69053888fea98f5dfe4c8af8b5a6360e0afb3b5d7 + title:King Arthur's World (USA) + cheat + description:Infinite men - if you have at least one of that type + code:8EA8-642F+8EAC-6F2F + cheat + description:Infinite spells - must have at least one to use + code:8EBC-6DEC + cheat + description:Start with 4 of each type of spell + code:C4EE-6D79+7DEE-6D59+D4EE-6D89 + cheat + description:Start with many men + code:CBEB-6405+F0EB-6465+DDEB-64A5 + cheat + description:Start on training level 2 + code:F561-DD86 + cheat + description:Start on training level 3 + code:FB61-DD86 + cheat + description:Start on training level 4 + code:F161-DD86 + cheat + description:Start on training level 5 + code:F261-DD86 + cheat + description:Start on training level 6 + code:F361-DD86 + cheat + description:Start on training level 7 + code:FE61-DD86 + cheat + description:Start on training level 8 + code:4D61-DD86 + cheat + description:Start on training level 9 + code:FC61-DD86 + cheat + description:Start on real world level 1 + code:DF61-DD86 + cheat + description:Start on real world level 2 + code:D461-DD86 + cheat + description:Start on real world level 3 + code:D761-DD86 + cheat + description:Start on real world level 4 + code:D061-DD86 + cheat + description:Start on goblin underworld level 1 + code:D961-DD86 + cheat + description:Start on goblin underworld level 2 + code:D161-DD86 + cheat + description:Start on goblin underworld level 3 + code:D561-DD86 + cheat + description:Start on goblin underworld level 4 + code:D661-DD86 + cheat + description:Start on cloud world level 1 + code:DA61-DD86 + cheat + description:Start on cloud world level 2 + code:D261-DD86 + cheat + description:Start on cloud world level 3 + code:D361-DD86 + cheat + description:Start on cloud world level 4 + code:DE61-DD86 + cheat + description:Start on cloud world level 5 + code:FD61-DD86 + cheat + description:Start on cloud world level 6 + code:FF61-DD86 + cheat + description:Start on cloud world level 7 + code:F461-DD86 + +cartridge sha256:6638b5541059814d4c34574e5e277ef613aebf81c91d3def557a7642fb5840e1 + title:King of Dragons, The (USA) + cheat + description:Invincibility - both players + code:ED76-E4AF + cheat + description:Infinite health - both players + code:C9B5-7FDD + cheat + description:Infinite time + code:DD0E-EF0D + cheat + description:Infinite credits + code:CE05-8F0D + cheat + description:One hit kills + code:4069-EF64+4069-E4D4 + cheat + description:Hit anywhere + code:6D61-8DA4+6D64-87A4+6D66-87A4+6D6E-54D4+6D6E-5D04 + cheat + description:Start with level 6 Sword + code:6351-E40D+6955-EDDD + cheat + description:Start with level 6 Shield + code:6355-E7AD+6956-EF6D + cheat + description:Invincibility (blinking) - P1 + code:7E0BB4:FF + cheat + description:Invincibility (blinking) - P2 + code:7E0CB4:FF + cheat + description:Infinite health - P1 + code:7E0B9A:09 + cheat + description:Infinite health - P2 + code:7E0C9A:09 + cheat + description:Max attack - P1 + code:7E0BEE:07 + cheat + description:Max attack - P2 + code:7E0CEE:07 + cheat + description:Max defense - P1 + code:7E0BF0:07 + cheat + description:Max defense - P2 + code:7E0CF0:07 + cheat + description:Infinite lives - P1 + code:7E0BEC:09 + cheat + description:Infinite lives - P2 + code:7E0CEC:09 + cheat + description:Infinite time (alt) + code:7E1F94:98 + cheat + description:Infinite time for player select screen + code:7E5C24:0A + cheat + description:Start on stage 2 - Treasure In An Old Castle + code:7E0658:01 + cheat + description:Start on stage 3 - Battle On Mountain Peak + code:7E0658:02 + cheat + description:Start on stage 4 - Cave Of Hydra + code:7E0658:03 + cheat + description:Start on stage 5 - To The Norde Isle + code:7E0658:04 + cheat + description:Start on stage 6 - The Giant In The Shrine + code:7E0658:05 + cheat + description:Start on stage 7 - Trent Woods + code:7E0658:06 + cheat + description:Start on stage 8 - To The Castle + code:7E0658:07 + cheat + description:Start on stage 9 - In The Castle + code:7E0658:08 + cheat + description:Start on stage 10 - Underpass + code:7E0658:09 + cheat + description:Start on stage 11 - Battle In The Front + code:7E0658:0A + cheat + description:Start on stage 12 - Castle Garenos + code:7E0658:0B + cheat + description:Start on stage 13 - Dark Wizard + code:7E0658:0C + cheat + description:Start on stage 14 - A Cave In The Woods + code:7E0658:0D + cheat + description:Start on stage 15 - Underground Labyrinth + code:7E0658:0E + cheat + description:Start on stage 16 - Golden Limestone Cave + code:7E0658:0F + +cartridge sha256:1135858a1ce686a0a163bb0e6f3a4d7cd71c0cd56efbc79677372f2624cf2306 + title:King of the Monsters (USA) + cheat + description:Faster timer + code:F5AF-D5A1 + cheat + description:Slower timer + code:1DAF-DFA1 + cheat + description:3 power points needed to get to next power level + code:D7A1-0DA1 + cheat + description:Start with less health - P1 + code:6DB2-AF67 + cheat + description:Start with less health - P2 + code:6DC4-D764 + cheat + description:Infinite health - P1 + code:7E0A50:FF + cheat + description:No health - P2 + code:7E0B40:00 + cheat + description:Infinite time - minutes + code:7E29F3:09 + cheat + description:Infinite time - seconds + code:7E29F2:54 + +cartridge sha256:a9729d049ce580839bbfef1836a13dc16f2fc934d203ebf7390e0b1c47ea9a2d + title:King of the Monsters 2 (USA) + cheat + description:Infinite health + code:7E1A3A:18 + cheat + description:Infinite lives + code:7E09CC:03 + cheat + description:Infinite time + code:7E0942:69 + cheat + description:Always have 2 power-ups + code:7E1CB4:02 + +cartridge sha256:4e095fbbdec4a16b075d7140385ff68b259870ca9e3357f076dfff7f3d1c4a62 + title:Kirby Super Star (USA) + cheat + description:Infinite health + code:62E2-AD61 + cheat + description:Infinite lives + code:C263-AF02 + cheat + description:Always have invincibility + code:3035F1:0A + cheat + description:Infinite health (friend) + code:40137E:30 + +cartridge sha256:67937dd7a29a93b1aaabb6df89f0748369ff47f3f6c655a402c00d5657973140 + title:Kirby's Avalanche (USA) + cheat + description:Boulder warnings don't appear + code:80A8-C4CD + cheat + description:Only red blobs fall + code:CB60-C737+DD69-CD47+DD69-CD17 + cheat + description:Only yellow blobs fall + code:CB60-C737+DF69-CD47+DF69-CD17 + cheat + description:Only green blobs fall + code:CB60-C737+D769-CD47+D769-CD17 + cheat + description:Only purple blobs fall + code:CB60-C737+D069-CD47+D069-CD17 + cheat + description:Only blue blobs fall + code:CB60-C737+D969-CD47+D969-CD17 + cheat + description:Only red and yellow blobs fall + code:CB60-C737+DD69-CD47+DF69-CD17 + cheat + description:Only red and green blobs fall + code:CB60-C737+DD69-CD47+D769-CD17 + cheat + description:Only red and purple blobs fall + code:CB60-C737+DD69-CD47+D069-CD17 + cheat + description:Only red and blue blobs fall + code:CB60-C737+DD69-CD47+D969-CD17 + cheat + description:Only red blobs with a boulder fall + code:CB60-C737+DD69-CD47+D169-CD17 + cheat + description:Only yellow and red blobs fall + code:CB60-C737+DF69-CD47+DD69-CD17 + cheat + description:Only yellow and green blobs fall + code:CB60-C737+DF69-CD47+D769-CD17 + cheat + description:Only yellow and purple blobs fall + code:CB60-C737+DF69-CD47+D069-CD17 + cheat + description:Only yellow and blue blobs fall + code:CB60-C737+DF69-CD47+D969-CD17 + cheat + description:Only yellow blobs with a boulder fall + code:CB60-C737+DF69-CD47+D169-CD17 + cheat + description:Only green and yellow blobs fall + code:CB60-C737+D769-CD47+DF69-CD17 + cheat + description:Only green and red blobs fall + code:CB60-C737+D769-CD47+DD69-CD17 + cheat + description:Only green and purple blobs fall + code:CB60-C737+D769-CD47+D069-CD17 + cheat + description:Only green and blue blobs fall + code:CB60-C737+D769-CD47+D969-CD17 + cheat + description:Only green blobs with a boulder fall + code:CB60-C737+D769-CD47+D169-CD17 + cheat + description:Only purple and yellow blobs fall + code:CB60-C737+D069-CD47+DF69-CD17 + cheat + description:Only purple and green blobs fall + code:CB60-C737+D069-CD47+D769-CD17 + cheat + description:Only purple and red blobs fall + code:CB60-C737+D069-CD47+DD69-CD17 + cheat + description:Only purple and blue blobs fall + code:CB60-C737+D069-CD47+D969-CD17 + cheat + description:Only purple blobs with a boulder fall + code:CB60-C737+D069-CD47+D169-CD17 + cheat + description:Only blue and yellow blobs fall + code:CB60-C737+D969-CD47+DF69-CD17 + cheat + description:Only blue and green blobs fall + code:CB60-C737+D969-CD47+D769-CD17 + cheat + description:Only blue and purple blobs fall + code:CB60-C737+D969-CD47+D069-CD17 + cheat + description:Only blue and red blobs fall + code:CB60-C737+D969-CD47+DD69-CD17 + cheat + description:Only blue blobs with a boulder fall + code:CB60-C737+D969-CD47+D169-CD17 + cheat + description:Only a boulder and yellow blobs fall + code:CB60-C737+D169-CD47+DF69-CD17 + cheat + description:Only a boulder and green blobs fall + code:CB60-C737+D169-CD47+D769-CD17 + cheat + description:Only a boulder and purple blobs fall + code:CB60-C737+D169-CD47+D069-CD17 + cheat + description:Only a boulder and blue blobs fall + code:CB60-C737+D169-CD47+D969-CD17 + cheat + description:Only a boulder and red blobs fall + code:CB60-C737+D169-CD47+DD69-CD17 + cheat + description:Only boulders fall + code:CB60-C737+D169-CD47+D169-CD17 + cheat + description:Disable the next box + code:CBB7-4D4D+3CB7-4DCD+CBB7-4F1D+3CB7-4F3D + +cartridge sha256:0f984dc5fe8293f75e3b8fad98b0cb564706d9b1e3902b56415aa399c2d4df2b + title:Kirby's Dream Course (USA) + cheat + description:Infinite Strawberries + code:82CF-4D6E + cheat + description:Don't lose a life from falling out of bounds + code:82E2-4DD4 + cheat + description:Don't ever gain any Strawberries + code:82CD-4D0E + cheat + description:Start with 5 lives + code:D0A9-4F6D + cheat + description:Start with 7 lives + code:D1A9-4F6D + cheat + description:Start with 9 lives + code:D6A9-4F6D + cheat + description:Start with 1 Strawberry + code:DFAD-1F0D + cheat + description:Start with 2 Strawberries + code:D4AD-1F0D + cheat + description:Start with 3 Strawberries + code:D7AD-1F0D + cheat + description:Infinite Tomatoes + code:83AC12:BD + +cartridge sha256:b50bf9d95485e8aeb7a6730e9f9f9c9c4ec23a85b336a4fb2e3b63034531e36f + title:Kirby's Dream Land 3 (USA) + cheat + description:Always have Invincibility - Kirby + code:4054B2:01 + cheat + description:Infinite life - Kirby + code:4039D1:0A + cheat + description:Infinite life - Partner + code:4039D3:08 + cheat + description:Infinite lives + code:4039CF:0A + cheat + description:Infinite Mouth Shot + code:4054ED:02 + cheat + description:Always have No Mouth power + code:4054A9:00 + cheat + description:Always have Fireball Mouth power + code:4054A9:01 + cheat + description:Always have Stone Mouth power + code:4054A9:02 + cheat + description:Always have Ice Mouth power + code:4054A9:03 + cheat + description:Always have Needle Mouth power + code:4054A9:04 + cheat + description:Always have Broom Mouth power + code:4054A9:05 + cheat + description:Always have Parasol Mouth power + code:4054A9:06 + cheat + description:Always have Spark Mouth power + code:4054A9:07 + cheat + description:Always have Boomerang Mouth power + code:4054A9:08 + cheat + description:Have all level 1 Stars + code:4053A7:01+4053A8:01+4053A9:01+4053AA:01+4053AB:01+4053AC:01 + cheat + description:Have all level 2 Stars + code:4053AE:01+4053AF:01+4053B0:01+4053B1:01+4053B2:01+4053B3:01 + cheat + description:Have all level 3 Stars + code:4053B5:01+4053B6:01+4053B7:01+4053B8:01+4053B9:01+4053BA:01 + cheat + description:Have all level 4 Stars + code:4053BC:01+4053BD:01+4053BE:01+4053BF:01+4053C0:01+4053C1:01 + cheat + description:Have all level 5 Stars + code:4053C3:01+4053C4:01+4053C5:01+4053C6:01+4053C7:01+4053C8:01 + cheat + description:Start a new game with 9 lives + code:DC85-64D4 + cheat + description:Start a new game with 25 lives + code:FC85-64D4 + cheat + description:Start a new game with 98 lives + code:1785-64D4 + +cartridge sha256:fb601ead645edce139b0483d3155b4e3d7ab245bf87a3a66cb88c0a617c0a526 + title:Knights of the Round (USA) + cheat + description:Invincibility + code:ED2F-3FD9 + cheat + description:More invincibility time after successful block + code:EE2C-C7DC + cheat + description:Infinite health + code:8B29-4D65 + cheat + description:Almost infinite health + code:4029-4DD5+4022-1DD5 + cheat + description:Maximum health from most food + code:DDAD-17BF + cheat + description:Infinite lives + code:8B27-4F68 + cheat + description:Infinite time + code:C26C-47AF + cheat + description:One hit kills + code:4027-37A5+4038-C760+4033-4760 + cheat + description:No health lost from special move + code:DD2A-3406 + cheat + description:No health lost from special move (alt) + code:8B2A-34A6 + cheat + description:Less health lost from special move + code:D12A-3406 + cheat + description:More health lost from special move + code:F02A-3406 + cheat + description:Super-jump - Arthur + code:DAC9-1DDB + cheat + description:Super-jump - Lancelot + code:DAC0-17DB + cheat + description:Super-jump - Percival + code:DAC9-1FDB + cheat + description:Slower timer + code:1D6B-47AF + cheat + description:Faster timer + code:F36B-47AF + cheat + description:Enable hidden options screen in the options menu + code:4DA1-14DD+84A1-140D+ABA1-146D+1DA8-14D4 + cheat + description:Start on stage 2 + code:3C81-4461+CB81-44A1+DF81-47D1 + cheat + description:Start on stage 3 + code:3C81-4461+CB81-44A1+D481-47D1 + cheat + description:Start on stage 4 + code:3C81-4461+CB81-44A1+D781-47D1 + cheat + description:Start on stage 5 + code:3C81-4461+CB81-44A1+D081-47D1 + cheat + description:Start on stage 6 + code:3C81-4461+CB81-44A1+D981-47D1 + cheat + description:Invincibility (blinking) - P1 + code:7E4136:02 + cheat + description:Invincibility (blinking) - P2 + code:7E4336:02 + cheat + description:Infinite health (alt) + code:7E4008:50 + cheat + description:Infinite time (alt) + code:7E0C4A:59 + cheat + description:Quick level gain - P1 + code:7E4149:00+7E414A:00+7E414B:00+7E414C:00 + cheat + description:Quick level gain - P2 + code:7E4349:00+7E434A:00+7E434B:00+7E434C:00 + +cartridge sha256:6a37a20a4880b9ec38b1b7e17e42ea93a1bf826630ccbe5f8257f0d928f13953 + title:Kouryuu no Mimi (Japan) + cheat + description:Infinite health + code:CB6D-1F24+0D6D-14F4+DD6D-1494+626D-17F4 + cheat + description:Infinite health (alt) + code:7E09C0:40 + cheat + description:Infinite Ring power + code:7E008C:20 + +cartridge sha256:e36322697c48baae6492db91e6cbf3844a420f6e0cc8a75f3a73556026ddbbb8 + title:Krusty's Super Fun House (USA) (Rev 1) + cheat + description:Infinite lives + code:7E11A3:03 + cheat + description:Infinite weapons + code:7E032C:0A + +cartridge sha256:bed18c968aee0eb0c866c1964c28135364cd6d65fff7bcb5873342c04e63750d + title:Krusty's Super Fun House (USA) + cheat + description:Invincibility - Krusty + code:8725-0D64 + cheat + description:Infinite Custard Pies + code:C1E1-D7DD + cheat + description:Infinite Superballs + code:C1E2-D76D + cheat + description:Infinite lives + code:C265-0FA7 + cheat + description:Custard Pie bonus worth 2 pies instead of 10 + code:D43D-67D7 + cheat + description:Custard Pie bonus worth 5 pies + code:D93D-67D7 + cheat + description:Custard Pie bonus same as Superball bonus (disable is game freezes) + code:D03D-6767 + cheat + description:Superball bonus worth 2 balls instead of 5 (disable is game freezes) + code:D43F-6F67 + cheat + description:Superball bonus worth 10 balls (disable is game freezes) + code:DC3F-6F67 + cheat + description:Superball bonus same as Custard Pie bonus (disable is game freezes) + code:6D3F-6DA7+E03F-6FD7 + cheat + description:Food bonuses restore less strength + code:D53E-0407 + cheat + description:Food bonuses restore more strength + code:F33E-0407 + cheat + description:Food bonuses restore Krusty to full strength + code:173E-0407 + cheat + description:Food bonuses also get Custard Pie bonus + code:D03D-6FD7 + cheat + description:Food bonuses also get Superball bonus + code:D33D-6FD7 + cheat + description:Doll bonus same as Custard Pie bonus + code:3134-6D67+6D34-6D07 + cheat + description:Doll bonus same as Superball bonus + code:ED34-6D67+6D34-6D07 + cheat + description:Doll bonus same as food bonus + code:2F34-6D67+6D34-6D07 + cheat + description:Jump higher - Krusty + code:FD3C-D704 + cheat + description:Jump much higher - Krusty + code:D63C-D704 + cheat + description:Start with section 1 finished + code:DD65-67DF+6D65-670F+D965-676F + cheat + description:Start with section 2 finished + code:DF65-67DF+6D65-670F+D965-676F + cheat + description:Start with section 3 finished + code:D465-67DF+6D65-670F+D965-676F + cheat + description:Start with section 4 finished + code:D765-67DF+6D65-670F+D965-676F + cheat + description:Start with access to all sections + code:D065-67DF+6D65-670F+D965-676F + cheat + description:Start with 1 life instead of 3 + code:DF6C-D704 + cheat + description:Start with 2 lives + code:D46C-D704 + cheat + description:Start with 5 lives + code:D96C-D704 + cheat + description:Start with 7 lives + code:D56C-D704 + cheat + description:Start with 9 lives + code:DB6C-D704 + cheat + description:Start with 0 Custard Pies + code:DD6B-D764 + cheat + description:Start with 2 Custard Pies + code:D46B-D764 + cheat + description:Start with 5 Custard Pies + code:D96B-D764 + cheat + description:Start with 2 Superballs instead of 10 Custard Pies + code:D46B-D764+DF6C-DDA4 + cheat + description:Start with 5 Superballs + code:D96B-D764+DF6C-DDA4 + cheat + description:Start with 10 Superballs + code:DF6C-DDA4 + +cartridge sha256:46c811f0cacffe8f20e1d63072d25d7c47e9bb3fd5124851fd05aca9884d21fb + title:Lagoon (USA) + cheat + description:HP always recovers instantly + code:CBB0-0FA0+EEB0-04D0 + cheat + description:MP always recovers instantly + code:CBB0-07A0+EEB9-0DD0 + cheat + description:Save always available + code:6D8A-6FA8+F78A-64D8 + cheat + description:Pit death disabled + code:1DA9-04D1 + cheat + description:Get 1 gold for each creature killed + code:1BB5-D769+DFB5-D7A9+3CB6-DDD9 + cheat + description:Get 100 gold for each creature killed + code:1BB5-D769+10B5-D7A9+3CB6-DDD9 + cheat + description:Get 200 gold for each creature killed + code:1BB5-D769+A6B5-D7A9+3CB6-DDD9 + cheat + description:Start with 0 STR + code:DD23-07DC + cheat + description:Start with 100 STR + code:1023-07DC + cheat + description:Start with 255 STR + code:EE23-07DC + cheat + description:Start with 0 DEF + code:DD2E-04AC + cheat + description:Start with 100 DEF + code:102E-04AC + cheat + description:Start with 255 DEF + code:EE2E-04AC + cheat + description:Start with 999 DEF + code:E12E-07DC+F52E-04AC + cheat + description:Start with 612 gold + code:D42D-6D6C + cheat + description:Start with 1,380 gold + code:D92D-6D6C + cheat + description:Start with 2,148 gold + code:D62D-6D6C + cheat + description:Start with 8,292 gold + code:4D2D-6D6C + cheat + description:Start with 22,116 gold + code:912D-6D6C + cheat + description:Start with 65,380 gold + code:EE2D-6D6C + cheat + description:Start on level 2, MP = 8/8, HP = 17/17, EXP = 0/40 + code:D422-040C + cheat + description:Start on level 3, MP = 10/10, HP = 23/23, EXP = 0/90 + code:D722-040C + cheat + description:Start on level 4, MP = 12/12, HP = 28/28, EXP = 0/170 + code:D022-040C + cheat + description:Start on level 5, MP = 19/19, HP =36/36, EXP = 0/280 + code:D922-040C + cheat + description:Start on level 241, HP = 255, MP = 255, EXP = 22859, walk at a regular speed + code:EF22-040C + cheat + description:Start on level 242, HP = 220, MP = 221, EXP = 30560, walk at a medium speed + code:E422-040C + cheat + description:Infinite HP + code:7E0520:FF + cheat + description:Infinite MP + code:7E0522:FF + cheat + description:Have all equipment and magic + code:7E04D0:FF+7E04D1:FF+7E04D2:FF+7E04D3:F8 + cheat + description:Have all items + code:7E04D4:FF+7E04D5:FF+7E04D6:FF+7E04D7:80 + cheat + description:Shop item 1 free + code:7E045C:00+7E045D:00 + cheat + description:Shop item 2 free + code:7E045E:00+7E045F:00 + cheat + description:Shop item 3 free + code:7E0460:00+7E0461:00 + cheat + description:Max EXP + code:7E052A:FF+7E052B:FF + cheat + description:Max level (level 35) + code:7E052C:23 + cheat + description:Max STR + code:7E0525:02 + cheat + description:Max DEF + code:7E0527:02 + cheat + description:Max Gold + code:7E0529:FF + +cartridge sha256:48cd9476fef1ed685b9c30dd1669b46048f7295cbbb2abcfa5b1a48699346ea3 + title:Lamborghini American Challenge (USA) + cheat + description:Always finish first + code:58E6-CF18+6D60-C71C+ADE6-CD48+BBE6-CF38+DDE6-CD18+DDE6-CDC8+D4E6-CF48+E360-C7CC+F1E6-C418+FCE6-CFC8+1DE6-C4C8+2DE6-CD38+4D60-C74C+53E6-C448 + cheat + description:Don't take damage in races + code:8B81-34D7 + cheat + description:Free turbos + code:C22A-377D + cheat + description:Repair 10% of car for $100 + code:C224-CF8F + cheat + description:Repair 10% of car for free + code:3324-C45F + cheat + description:Turbos for $1000 + code:DC28-348D+DD28-34ED + cheat + description:Turbos for $2000 + code:F028-348D+DD28-34ED + cheat + description:Start with 6-speed transmission + code:D169-443B + cheat + description:Start with $128,000 + code:DD6E-440D+D96E-446D + cheat + description:Start with $88,000 + code:5D6E-440D+D76E-446D + cheat + description:Start with $12,800 + code:6D6E-440D + cheat + description:Always finish first (alt) + code:7E167E:01 + cheat + description:Infinite money + code:7E0D21:FF+7E0D22:FF + cheat + description:Infinite Boost + code:7E0DDD:09 + +cartridge sha256:314d53f409b66ba3f4426a6f1bb7c69f6779aeed277ce2e19535f94d7c8ca586 + title:Last Action Hero (USA) + cheat + description:Invincibility + code:62AF-140D + cheat + description:Infinite health + code:C2A0-1D6D + cheat + description:Infinite time + code:C2BF-1FAF + cheat + description:Infinite lives + code:A2CB-4FAF + cheat + description:Invincibility (blinking) + code:7E03B7:FF + cheat + description:Infinite health (alt) + code:7E031F:FF + cheat + description:Infinite time (alt) + code:7E0315:99 + cheat + description:Infinite lives (alt) + code:7E0316:04 + cheat + description:One hit kills - enemy 1 + code:7E0822:00 + cheat + description:One hit kills - enemy 2 + code:7E0880:00 + cheat + description:One hit kills - enemy 3 + code:7E08DE:00 + cheat + description:Start on stage 2 + code:7E030F:02 + cheat + description:Start on stage 3 + code:7E030F:03 + cheat + description:Start on stage 4 + code:7E030F:04 + cheat + description:Start on stage 5 + code:7E030F:05 + +cartridge sha256:a179a1188220b59787c49a78a0dde79b89380e3a8a8a0ab558f0102c5796f873 + title:Lawnmower Man, The (USA) + cheat + description:Invincible in Cyber Run level + code:C268-17AC + cheat + description:Invincible in Cyber Tube level + code:C26A-CD6C + cheat + description:Invincible in Cyber Jobe level + code:C223-1DD5 + cheat + description:Invincible in Cyber Space level + code:C2A2-479C + cheat + description:Infinite lives + code:40BE-1DAD + cheat + description:After you die, your main weapon is fully powered up from then on + code:D0B5-CDAD+CBB5-CD6D + cheat + description:Super-jump + code:ECB6-4FD7 + cheat + description:Energize icon effect lasts 2x longer + code:D785-376F + cheat + description:Energize icon effect lasts 4x longer + code:D985-376F + cheat + description:Bitstream powers up instantly (don't shoot too many bitstreams at once) + code:D1BB-4F64 + cheat + description:Keep weapon power ups once gained + code:DDB5-CDAD + cheat + description:Never lose homing bullets once gained + code:CEB7-CFAD + cheat + description:Never lose rear bullets once gained + code:CEB7-CDAD + +cartridge sha256:c7814cee0fc95d6422cf19a3dc8c9a65b60f6f56da75f09cebea02cc5f99261b + title:Legend (USA) + cheat + description:Invincibility + code:62A6-3FAD+29A6-34DD+F7A6-340D + cheat + description:Infinite health + code:C2EB-1709 + cheat + description:Infinite time + code:C23F-1DDD + cheat + description:Infinite lives + code:C289-1DD7 + cheat + description:One hit kills + code:40C6-C469+4081-1F69 + cheat + description:Infinite health - P1 + code:7E130D:08 + cheat + description:Infinite magic - P1 + code:7E1315:09 + cheat + description:Infinite lives - P1 + code:7E1309:09 + cheat + description:Infinite time (alt) + code:7E15EF:09 + cheat + description:Infinite Keys - P1 + code:7E12F1:63 + +cartridge sha256:c865fb17e8c59a21d32b9a605319241fa74ec732e3f0ee58f5d7fcbd8ee57c6b + title:Legend of the Mystical Ninja, The (USA) + cheat + description:Infinite health + code:89CF-0729 + cheat + description:Infinite lives - top-view stages + code:3CA6-A764 + cheat + description:Don't lose most weapons when hit + code:40C0-04F9 + cheat + description:Die after one hit + code:DDCF-0429 + cheat + description:Pick-up more coins from enemies + code:9DAF-DD6E + cheat + description:No coins used up when thrown + code:DDED-D4D4 + cheat + description:Faster timer + code:F0BE-AF20 + cheat + description:Slower timer + code:1DBE-AF20 + cheat + description:Start with 6 lives + code:D927-A464 + cheat + description:Start with 9 lives + code:D627-A464 + cheat + description:Invincibility - P1 + code:7E0592:02 + cheat + description:Infinite health - P1 + code:7E1AB2:10 + cheat + description:Infinite money - P1 + code:7E1AAC:99+7E1AAD:99+7E1AAE:09 + cheat + description:Infinite lives - P1 + code:7E1AB0:04 + cheat + description:Have Jutsu technique 1 + code:7E1AD6:01 + cheat + description:Have Jutsu technique 2 + code:7E1AD8:01 + cheat + description:Have Jutsu technique 3 + code:7E1ADA:01 + cheat + description:Have Jutsu technique 4 + code:7E1ADC:01 + cheat + description:Have 1st upgraded weapon + code:7E1AB6:01+7E1AB8:01 + cheat + description:Have 2nd upgraded weapon + code:7E1AB6:02+7E1AB8:02 + cheat + description:Infinite Bombs + code:7E1ABA:30 + cheat + description:Have Gold Helmet + code:7E1AE0:08 + cheat + description:Have Iron Helmet + code:7E1AE2:06 + cheat + description:Have Straw Hat + code:7E1AE4:04 + cheat + description:Have Gold Armor + code:7E1AF0:08 + cheat + description:Have Chain Armor + code:7E1AF2:06 + cheat + description:Have Straw Coat + code:7E1AF4:04 + cheat + description:Have whole Pizza + code:7E1B10:01 + cheat + description:Have slice of Pizza + code:7E1B12:01 + cheat + description:Have Burger + code:7E1B14:01 + cheat + description:Have Pass + code:7E1B20:01 + cheat + description:Have Text + code:7E1B22:01 + cheat + description:Max walking speed + code:7E1AC2:02+7E1B00:03 + +cartridge sha256:66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb + title:Legend of Zelda, The - A Link to the Past (USA) + cheat + description:Invincibility + code:1CDF-2EE6 + cheat + description:Infinite rupees + code:35E1-2A76 + cheat + description:Infinite health and all heart containers + code:CDE1-2E56 + cheat + description:Almost infinite health + code:AE6E-DF2A + cheat + description:Infinite magic + code:6DE1-2E86 + cheat + description:Almost infinite magic + code:AE8A-D4FA+AE8D-0D9A + cheat + description:Max heart containers + code:CDEE-DDBF + cheat + description:Infinite Bombs + code:AE67-0D30 + cheat + description:Infinite Bombs (alt) + code:17E0-2AE6 + cheat + description:Infinite Arrows + code:17E5-22E6 + cheat + description:Hit anywhere (disable before fighting Ganon, use the Boomerang instead of Sword to hit switches) + code:40E2-6D96+6D3E-A7FC+403F-DD28+40EC-AF26+6D34-D7F8+4068-A0E6 + cheat + description:Get items from anywhere + code:402F-07B6 + cheat + description:Regular sword is very strong (100 damage instead of 2) + code:108E-D481 + cheat + description:Blue Boomerang has much longer reach + code:82BD-6F4D + cheat + description:Enemies frozen by Boomerang or Hookshot stay frozen + code:8234-AD96 + cheat + description:Sword can destroy solid objects in Overworld + code:6D87-611E + cheat + description:Objects that you can pick up and throw never break away + code:FD37-6FF6 + cheat + description:Dash without having the Pegasus Boots + code:EEE5-2356 + cheat + description:Use the Magic Mirror to warp between the Light and Dark Worlds freely + code:6DC9-0D23 + cheat + description:Some shops don't take your money + code:AEEC-A586 + cheat + description:Spin attack needs nearly no time to charge + code:D6B5-049E + cheat + description:Spin attack needs no time at all to charge + code:DDB5-049E + cheat + description:100% enemy drop rate (from enemies that normally drop items) + code:DDE8-142C + cheat + description:No enemies in dungeons + code:D9D7-9A78+D9D7-9A58+D9D7-9A88 + cheat + description:Dark rooms are fully lit + code:D7D9-F38B + cheat + description:Trigger doors are open (works with most dungeon doors, some that even look closed) + code:EED6-BE5B + cheat + description:Have Bombos Medallion + code:DFE0-22E6 + cheat + description:Have Book Of Mudora + code:DFE0-2E86 + cheat + description:Have Bug-Catching Net + code:DFE0-2E56 + cheat + description:Have Cane Of Byrna + code:DFE9-2A56 + cheat + description:Have Cane Of Somaria + code:DFE9-2A76 + cheat + description:Have Ether Medallion + code:DFE0-2376 + cheat + description:Have Fire Rod + code:DFE0-2256 + cheat + description:Have Flute + code:D4E0-2E76 + cheat + description:Have Flute with Duck + code:D7E0-2E76 + cheat + description:Have Golden Sword (level 4) + code:D0E9-2356 + cheat + description:Have Hookshot + code:DFE0-2A86 + cheat + description:Have Ice Rod + code:DFE0-2286 + cheat + description:Have Lamp + code:DFE0-2386 + cheat + description:Have Magic Boomerang + code:D4E0-2A56 + cheat + description:Have Magic Cape + code:DFE9-2A86 + cheat + description:Have Magic Hammer + code:DFE0-23E6 + cheat + description:Have Magic Mirror + code:D4E9-2AE6 + cheat + description:Have Magic Powder + code:D4E0-2276 + cheat + description:Have Mirror Shield + code:D7E9-2386 + cheat + description:Have Moon Pearl + code:DFE9-22E6 + cheat + description:Have Pegasus Boots + code:D4E9-2256 + cheat + description:Have Quake Medallion + code:DFE0-2356 + cheat + description:Have Red Mail + code:D4E9-23E6 + cheat + description:Have Shovel + code:DFE0-2E76 + cheat + description:Have Titan's Mitten + code:D4E9-2276 + cheat + description:Have Zora's Flippers + code:DFE9-2286 + cheat + description:Have 1/2 Magic curse + code:DFE5-23E6 + cheat + description:Have all abilities except Lift + code:1EE5-2356 + cheat + description:Have all Maps, Compasses and Big Keys + code:EEE1-2276+EEE1-2256+EEE1-2286+EEE1-22E6+EEE1-2376+EEE1-2356 + cheat + description:Invincibility (alt) + code:7E031F:10 + cheat + description:Invincibility (alt 2) + code:7E031F:01 + cheat + description:Infinite rupees (alt) + code:7EF360:E7+7EF361:03 + cheat + description:Infinite Keys + code:7EF36F:09 + cheat + description:Bombs full + code:7EF375:01 + cheat + description:Play chest game for free and able to open all chests + code:7E04C4:01 + cheat + description:Infinite time for digging game in the Dark World + code:7E04B4:1E + cheat + description:Always get Faerie at the Pond Of Happiness (as if you threw in 100 rupees) + code:7EF36A:64 + cheat + description:Luck modifier - Great + code:7E0CF9:01 + cheat + description:Luck modifier - Big Trouble + code:7E0CF9:02 + cheat + description:Turn rain on + code:7E001D:01 + cheat + description:Turn rain off + code:7E001D:00 + cheat + description:Walk through walls + code:07CB9A:EA+07CB9B:EA+07C1FA:EA+07C1FB:EA + cheat + description:Walk faster + code:7E005E:16 + cheat + description:Walk much faster + code:7E005E:10 + cheat + description:Have 20 Heart Containers and infinite health + code:7EF36D:A0 + cheat + description:Have Blue Mail + code:7EF35B:02 + cheat + description:Have Boomerang + code:7EF341:01 + cheat + description:Have Bow + code:7EF340:01 + cheat + description:Have Bow with Arrows + code:7EF340:02 + cheat + description:Have Bow with Silver Arrows + code:7EF340:04 + cheat + description:Have all Lift abilities + code:D7E9-2276 + cheat + description:Have all Crystals + code:7EF37A:7F + cheat + description:Have all Pendants + code:7EF374:47 + cheat + description:Have Small Key In dungeons + code:7EF36F:09 + cheat + description:Have Big Key in dungeons + code:7EF366:FF+7EF367:FF + cheat + description:Have Compass in dungeons + code:7EF365:FF + cheat + description:Have bottle 1 + code:7EF35C:02 + cheat + description:Have bottle 1 with infinite Mushrooms + code:7EF35C:01 + cheat + description:Have bottle 1 with infinite Red Medicine (life) + code:7EF35C:03 + cheat + description:Have bottle 1 with infinite Green Medicine (magic) + code:7EF35C:04 + cheat + description:Have bottle 1 with infinite Blue Medicine (cure all) + code:7EF35C:05 + cheat + description:Have bottle 1 with infinite Faeries + code:7EF35C:06 + cheat + description:Have bottle 1 with infinite Bees + code:7EF35C:07 + cheat + description:Have bottle 1 with infinite Good Bees + code:7EF35C:08 + cheat + description:Have bottle 2 + code:7EF35D:02 + cheat + description:Have bottle 2 with infinite Mushrooms + code:7EF35D:01 + cheat + description:Have bottle 2 with infinite Red Medicine (life) + code:7EF35D:03 + cheat + description:Have bottle 2 with infinite Green Medicine (magic) + code:7EF35D:04 + cheat + description:Have bottle 2 with infinite Blue Medicine (cure all) + code:7EF35D:05 + cheat + description:Have bottle 2 with infinite Faeries + code:7EF35D:06 + cheat + description:Have bottle 2 with infinite Bees + code:7EF35D:07 + cheat + description:Have bottle 2 with infinite Good Bees + code:7EF35D:08 + cheat + description:Have bottle 3 + code:7EF35E:02 + cheat + description:Have bottle 3 with infinite Mushrooms + code:7EF35E:01 + cheat + description:Have bottle 3 with infinite Red Medicine (life) + code:7EF35E:03 + cheat + description:Have bottle 3 with infinite Green Medicine (magic) + code:7EF35E:04 + cheat + description:Have bottle 3 with infinite Blue Medicine (cure all) + code:7EF35E:05 + cheat + description:Have bottle 3 with infinite Faeries + code:7EF35E:06 + cheat + description:Have bottle 3 with infinite Bees + code:7EF35E:07 + cheat + description:Have bottle 3 with infinite Good Bees + code:7EF35E:08 + cheat + description:Have bottle 4 + code:7EF35F:02 + cheat + description:Have bottle 4 with infinite Mushrooms + code:7EF35F:01 + cheat + description:Have bottle 4 with infinite Red Medicine (life) + code:7EF35F:03 + cheat + description:Have bottle 4 with infinite Green Medicine (magic) + code:7EF35F:04 + cheat + description:Have bottle 4 with infinite Blue Medicine (cure all) + code:7EF35F:05 + cheat + description:Have bottle 4 with infinite Faeries + code:7EF35F:06 + cheat + description:Have bottle 4 with infinite Bees + code:7EF35F:07 + cheat + description:Have bottle 4 with infinite Good Bees + code:7EF35F:08 + +cartridge sha256:cd016c41c7ef9f4f243d57c2b1564b4ceb3b4c38cc165cd02ab6c8e35c93aa2e + title:Lemmings (USA) (Rev 1) + cheat + description:Infinite climbers if you start with at least 1 + code:C984-A467 + cheat + description:Infinite floaters if you start with at least 1 + code:C98F-AD07 + cheat + description:Infinite bombers if you start with at least 1 + code:C987-A407 + cheat + description:Infinite blockers if you start with at least 1 + code:C984-6DA7 + cheat + description:Infinite builders if you start with at least 1 + code:C98E-6D07 + cheat + description:Infinite bashers if you start with at least 1 + code:C982-6FD7 + cheat + description:Infinite miners if you start with at least 1 + code:C981-67D7 + cheat + description:Infinite diggers if you start with at least 1 + code:C98B-64A7 + cheat + description:Each saved lemming counts as two + code:31B6-6FAF+18B6-64DF + cheat + description:Start on Level 2; rating: Fun + code:CBCC-DD05+DFCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 3; rating: Fun + code:CBCC-DD05+D4CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 4; rating: Fun + code:CBCC-DD05+D7CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 5; rating: Fun + code:CBCC-DD05+D0CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 6; rating: Fun + code:CBCC-DD05+D9CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 7; rating: Fun + code:CBCC-DD05+D1CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 8; rating: Fun + code:CBCC-DD05+D5CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 9; rating: Fun + code:CBCC-DD05+D6CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 10; rating: Fun + code:CBCC-DD05+DBCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 11; rating: Fun + code:CBCC-DD05+DCCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 12; rating: Fun + code:CBCC-DD05+D8CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 13; rating: Fun + code:CBCC-DD05+DACC-DD65+C9C8-0FD5 + cheat + description:Start on Level 14; rating: Fun + code:CBCC-DD05+D2CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 15; rating: Fun + code:CBCC-DD05+D3CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 16; rating: Fun + code:CBCC-DD05+DECC-DD65+C9C8-0FD5 + cheat + description:Start on Level 17; rating: Fun + code:CBCC-DD05+FDCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 18; rating: Fun + code:CBCC-DD05+FFCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 19; rating: Fun + code:CBCC-DD05+F4CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 20; rating: Fun + code:CBCC-DD05+F7CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 21; rating: Fun + code:CBCC-DD05+F0CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 22; rating: Fun + code:CBCC-DD05+F9CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 23; rating: Fun + code:CBCC-DD05+F1CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 24; rating: Fun + code:CBCC-DD05+F5CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 25; rating: Fun + code:CBCC-DD05+F6CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 26; rating: Fun + code:CBCC-DD05+FBCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 27; rating: Fun + code:CBCC-DD05+FCCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 28; rating: Fun + code:CBCC-DD05+F8CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 29; rating: Fun + code:CBCC-DD05+FACC-DD65+C9C8-0FD5 + cheat + description:Start on Level 30; rating: Fun + code:CBCC-DD05+F2CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 1; rating: Tricky + code:CBCC-DD05+F3CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 2; rating: Tricky + code:CBCC-DD05+FECC-DD65+C9C8-0FD5 + cheat + description:Start on Level 3; rating: Tricky + code:CBCC-DD05+4DCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 4; rating: Tricky + code:CBCC-DD05+4FCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 5; rating: Tricky + code:CBCC-DD05+44CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 6; rating: Tricky + code:CBCC-DD05+47CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 7; rating: Tricky + code:CBCC-DD05+40CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 8; rating: Tricky + code:CBCC-DD05+49CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 9; rating: Tricky + code:CBCC-DD05+41CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 10; rating: Tricky + code:CBCC-DD05+45CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 11; rating: Tricky + code:CBCC-DD05+46CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 12; rating: Tricky + code:CBCC-DD05+4BCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 13; rating: Tricky + code:CBCC-DD05+4CCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 14; rating: Tricky + code:CBCC-DD05+48CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 15; rating: Tricky + code:CBCC-DD05+4ACC-DD65+C9C8-0FD5 + cheat + description:Start on Level 16; rating: Tricky + code:CBCC-DD05+42CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 17; rating: Tricky + code:CBCC-DD05+43CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 18; rating: Tricky + code:CBCC-DD05+4ECC-DD65+C9C8-0FD5 + cheat + description:Start on Level 19; rating: Tricky + code:CBCC-DD05+7DCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 20; rating: Tricky + code:CBCC-DD05+7FCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 21; rating: Tricky + code:CBCC-DD05+74CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 22; rating: Tricky + code:CBCC-DD05+77CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 23; rating: Tricky + code:CBCC-DD05+70CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 24; rating: Tricky + code:CBCC-DD05+79CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 25; rating: Tricky + code:CBCC-DD05+71CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 26; rating: Tricky + code:CBCC-DD05+75CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 27; rating: Tricky + code:CBCC-DD05+76CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 28; rating: Tricky + code:CBCC-DD05+7BCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 29; rating: Tricky + code:CBCC-DD05+7CCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 30; rating: Tricky + code:CBCC-DD05+78CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 1; rating: Taxing + code:CBCC-DD05+7ACC-DD65+C9C8-0FD5 + cheat + description:Start on Level 2; rating: Taxing + code:CBCC-DD05+72CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 3; rating: Taxing + code:CBCC-DD05+73CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 4; rating: Taxing + code:CBCC-DD05+7ECC-DD65+C9C8-0FD5 + cheat + description:Start on Level 5; rating: Taxing + code:CBCC-DD05+0DCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 6; rating: Taxing + code:CBCC-DD05+0FCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 7; rating: Taxing + code:CBCC-DD05+04CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 8; rating: Taxing + code:CBCC-DD05+07CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 9; rating: Taxing + code:CBCC-DD05+00CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 10; rating: Taxing + code:CBCC-DD05+09CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 11; rating: Taxing + code:CBCC-DD05+01CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 12; rating: Taxing + code:CBCC-DD05+05CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 13; rating: Taxing + code:CBCC-DD05+06CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 14; rating: Taxing + code:CBCC-DD05+0BCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 15; rating: Taxing + code:CBCC-DD05+0CCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 16; rating: Taxing + code:CBCC-DD05+08CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 17; rating: Taxing + code:CBCC-DD05+0ACC-DD65+C9C8-0FD5 + cheat + description:Start on Level 18; rating: Taxing + code:CBCC-DD05+02CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 19; rating: Taxing + code:CBCC-DD05+03CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 20; rating: Taxing + code:CBCC-DD05+0ECC-DD65+C9C8-0FD5 + cheat + description:Start on Level 21; rating: Taxing + code:CBCC-DD05+9DCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 22; rating: Taxing + code:CBCC-DD05+9FCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 23; rating: Taxing + code:CBCC-DD05+94CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 24; rating: Taxing + code:CBCC-DD05+97CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 25; rating: Taxing + code:CBCC-DD05+90CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 26; rating: Taxing + code:CBCC-DD05+99CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 27; rating: Taxing + code:CBCC-DD05+91CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 28; rating: Taxing + code:CBCC-DD05+95CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 29; rating: Taxing + code:CBCC-DD05+96CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 30; rating: Taxing + code:CBCC-DD05+9BCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 1; rating: Mayhem + code:CBCC-DD05+9CCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 2; rating: Mayhem + code:CBCC-DD05+98CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 3; rating: Mayhem + code:CBCC-DD05+9ACC-DD65+C9C8-0FD5 + cheat + description:Start on Level 4; rating: Mayhem + code:CBCC-DD05+92CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 5; rating: Mayhem + code:CBCC-DD05+93CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 6; rating: Mayhem + code:CBCC-DD05+9ECC-DD65+C9C8-0FD5 + cheat + description:Start on Level 7; rating: Mayhem + code:CBCC-DD05+1DCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 8; rating: Mayhem + code:CBCC-DD05+1FCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 9; rating: Mayhem + code:CBCC-DD05+14CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 10; rating: Mayhem + code:CBCC-DD05+17CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 11; rating: Mayhem + code:CBCC-DD05+10CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 12; rating: Mayhem + code:CBCC-DD05+19CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 13; rating: Mayhem + code:CBCC-DD05+11CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 14; rating: Mayhem + code:CBCC-DD05+15CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 15; rating: Mayhem + code:CBCC-DD05+16CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 16; rating: Mayhem + code:CBCC-DD05+1BCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 17; rating: Mayhem + code:CBCC-DD05+1CCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 18; rating: Mayhem + code:CBCC-DD05+18CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 19; rating: Mayhem + code:CBCC-DD05+1ACC-DD65+C9C8-0FD5 + cheat + description:Start on Level 20; rating: Mayhem + code:CBCC-DD05+12CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 21; rating: Mayhem + code:CBCC-DD05+13CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 22; rating: Mayhem + code:CBCC-DD05+1ECC-DD65+C9C8-0FD5 + cheat + description:Start on Level 23; rating: Mayhem + code:CBCC-DD05+5DCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 24; rating: Mayhem + code:CBCC-DD05+5FCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 25; rating: Mayhem + code:CBCC-DD05+54CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 26; rating: Mayhem + code:CBCC-DD05+57CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 27; rating: Mayhem + code:CBCC-DD05+50CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 28; rating: Mayhem + code:CBCC-DD05+59CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 29; rating: Mayhem + code:CBCC-DD05+51CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 30; rating: Mayhem + code:CBCC-DD05+55CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 1; rating: Sunsoft + code:CBCC-DD05+56CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 2; rating: Sunsoft + code:CBCC-DD05+5BCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 3; rating: Sunsoft + code:CBCC-DD05+5CCC-DD65+C9C8-0FD5 + cheat + description:Start on Level 4; rating: Sunsoft + code:CBCC-DD05+58CC-DD65+C9C8-0FD5 + cheat + description:Start on Level 5; rating: Sunsoft + code:CBCC-DD05+5ACC-DD65+C9C8-0FD5 + cheat + description:Have a lot of time + code:7E0094:FF + cheat + description:Open all 'Fun' levels + code:7FFFC0:1E + cheat + description:Open all 'Tricky' levels + code:7FFFC1:1E + cheat + description:Open all 'Taxing' levels + code:7FFFC2:1E + cheat + description:Open all 'Mayhem' levels + code:7FFFC3:1E + cheat + description:Open all 'SUNSOFT' levels + code:7FFFC4:05 + cheat + description:Instantly win levels + code:7E0091:00 + cheat + description:0% Lemmings needed + code:7E0092:00 + cheat + description:Have 99 Climbers left + code:7E0095:63 + cheat + description:Have 99 Floaters left + code:7E0096:63 + cheat + description:Have 99 Exploders left + code:7E0097:63 + cheat + description:Have 99 Blockers left + code:7E0098:63 + cheat + description:Have 99 Builders left + code:7E0099:63 + cheat + description:Have 99 Bashers left + code:7E009A:63 + cheat + description:Have 99 Miners left + code:7E009B:63 + cheat + description:Have 99 Diggers left + code:7E009C:63 + cheat + description:Have 0 Lemmings left in level + code:7E0069:00 + cheat + description:Have 0 Lemmings left to enter level + code:7E006A:00 + cheat + description:Always rescued 100% of Lemmings + code:7E006B:64 + +cartridge sha256:a2c1970670e2831e47e24ced01bf4ba5aba05cac3773bf524c62d689c35687e1 + title:Lester the Unlikely (USA) + cheat + description:Infinite health against most enemies + code:C2C2-8DEB + cheat + description:Infinite lives + code:C2C6-7F58 + cheat + description:Flashing lasts a long time after getting hit + code:D0C2-848B + cheat + description:Flashing lasts a really long time after getting hit + code:DAC2-848B + cheat + description:Lighter gravity effect (disable right after pressing start, donï¾’t enable until first game play screen) + code:0DCA-5D5B + cheat + description:Even lighter gravity effect + code:49CA-5D5B + cheat + description:Amazingly lighter gravity effect + code:F9CA-5D5B + cheat + description:Infinite health + code:7E859B:03 + +cartridge sha256:3bc5f296c3dbee012e93a5cf25568f9288ce87b34d74085401a560350eaca03f + title:Lethal Enforcers (USA) + cheat + description:Infinite ammo + code:3CCE-C4AB + cheat + description:No damage from bad guys + code:3CB5-140C + cheat + description:No energy loss when you hit civilians + code:3CB2-446C + cheat + description:1/2 your energy is lost when you hit civilians + code:3CB2-446C + cheat + description:Play with more energy + code:F365-CF64+F362-CD64 + cheat + description:Keep weapon until you die + code:6DBF-1FAC + cheat + description:Magnum - more shots per round + code:DAA3-4F60 + cheat + description:Normal gun - more shots per round + code:DAA3-4D60 + cheat + description:Shotgun - more shots per round + code:DAA3-4460 + cheat + description:Invincibility - P1 + code:7E00B2:07 + cheat + description:Invincibility - P2 + code:7E00B4:07 + cheat + description:Infinite ammo for all guns - P1 + code:7E1FC0:06 + cheat + description:Infinite ammo for all guns - P2 + code:7E1FC2:06 + cheat + description:Have Grenade Launcher - P1 + code:7E1FBC:02 + cheat + description:Have Grenade Launcher - P2 + code:7E1FBE:02 + cheat + description:Have Magnum - P1 + code:7E1FBC:04 + cheat + description:Have Magnum - P2 + code:7E1FBE:04 + cheat + description:Have Shotgun - P1 + code:7E1FBC:06 + cheat + description:Have Shotgun - P2 + code:7E1FBE:06 + cheat + description:Have Automatic - P1 + code:7E1FBC:08 + cheat + description:Have Automatic - P2 + code:7E1FBE:08 + cheat + description:Have Glock 45 - P1 + code:7E1FBC:0A + cheat + description:Have Glock 45 - P2 + code:7E1FBE:0A + cheat + description:Have Uzi - P1 + code:7E1FBC:0C + cheat + description:Have Uzi - P2 + code:7E1FBE:0C + +cartridge sha256:80c22cc92d51a54de9cd9fd00db5ff58a35fff35e822169c94e445d50834fba3 + title:Lethal Weapon (USA) + cheat + description:Infinite health + code:4ABE-AFD7 + cheat + description:Infinite ammo + code:DD8D-D7A4 + cheat + description:Infinite time + code:C285-670F + cheat + description:More bullets in magazine + code:DB8F-DF64 + cheat + description:2 magazines on pick-up + code:D4CA-A7AF + cheat + description:4 magazines on pick-up + code:D0CA-A7AF + cheat + description:Slower timer + code:148B-6F0F + cheat + description:Faster timer + code:FE8B-6F0F + cheat + description:Super-jump (can get stuck) + code:3CBD-04DF + cheat + description:Start with more badges + code:D162-A7DF + cheat + description:Start with fewer badges + code:DD62-A7DF + cheat + description:Start with more magazine clips + code:DB6A-AF6F + cheat + description:Start with fewer magazine clips + code:DF6A-AF6F + cheat + description:Invincibility (blinking) + code:7E025E:50 + cheat + description:Infinite health (alt) + code:7E0226:06 + cheat + description:Infinite ammo (alt) + code:7E021E:07 + cheat + description:Infinite time (alt) + code:7E0D28:99+7E0D29:09 + cheat + description:Play as Riggs + code:7E0246:00 + cheat + description:Play as Murtaugh + code:7E0246:01 + +cartridge sha256:457abe634e0a8be03e29513a3dca8f3e9d0ddc6bf97d8931f2316094260f3712 + title:Lion King, The (USA) + cheat + description:Almost infinite health + code:C298-7DDE + cheat + description:Infinite lives + code:CE6E-8464 + cheat + description:Roaring doesn't decrease your roar meter + code:C291-5763 + cheat + description:Roar meter doesn't fill up with time + code:C289-5D6F + cheat + description:Don't lose roar power when you get hit + code:C293-E703 + cheat + description:higher-jump + code:CBF9-5D6A+E1F9-5DAA+EEF9-5FDA + cheat + description:Mega-jump + code:CBF9-5D6A+E0F9-5DAA+EEF9-5FDA + cheat + description:Walk through walls + code:6D6C-5D2D+DD67-5FBD+DDA2-EDAF + cheat + description:Invincibility (blinking) + code:7EB259:3D + cheat + description:Infinite health + code:7E2004:04 + cheat + description:Infinite Roar meter + code:7E2002:10 + cheat + description:Infinite lives (alt) + code:7FFFAA:09 + cheat + description:Infinite continues + code:7FFFA8:09 + cheat + description:Infinite time - Bug Hunt I + code:7EC0C1:28 + cheat + description:Infinite time - Bug Hunt II + code:7ECB41:28 + cheat + description:Infinite time - Bug Hunt III + code:7EBBC1:28 + cheat + description:Play as young Simba + code:7E2000:00 + cheat + description:Play as adult Simba + code:7E2001:FF + cheat + description:Start on The Pride Lands + code:7FFF9E:00 + cheat + description:Start on Roar At Monkeys + code:7FFF9E:01 + cheat + description:Start on The Elephant Graveyard + code:7FFF9E:02 + cheat + description:Start on The Stampede + code:7FFF9E:03 + cheat + description:Start on Simba's Exile + code:7FFF9E:04 + cheat + description:Start on Hakuna Matata + code:7FFF9E:05 + cheat + description:Start on Simba's Destiny + code:7FFF9E:06 + cheat + description:Start on Be Prepared + code:7FFF9E:07 + cheat + description:Start on Simba's Return + code:7FFF9E:08 + cheat + description:Start on Pride Rock + code:7FFF9E:09 + cheat + description:Start on Bug Toss + code:7FFF9E:0A + cheat + description:Start on Bug Hunt I + code:7FFF9E:0B + cheat + description:Start on Bug Hunt II + code:7FFF9E:0C + cheat + description:Start on Bug Hunt III + code:7FFF9E:0D + cheat + description:Start on Game Begins + code:7FFF9E:0E + cheat + description:Start on Kill Him + code:7FFF9E:0F + +cartridge sha256:52dbfdaca87debdf181b87d55192b0f8dd07e8aeb43afa4b04df16d44ec998e5 + title:Little Magic (Japan) + cheat + description:Infinite Mays / Retries + code:7E0059:09 + +cartridge sha256:7e1d6242ae2ec2c23afb876becdcf778098edd4d853234222dc16471cb51df9e + title:Lock On (USA) + cheat + description:Infinite Flares + code:7E1113:46 + cheat + description:Infinite Missile A + code:7E1115:46 + cheat + description:Infinite Missile B + code:7E1116:46 + cheat + description:Infinite lives + code:7E1106:0A + +cartridge sha256:9f7782a92fda789f9d119b1f0a2f7da0f35606357556a48eca9487797ee1a888 + title:Lost Vikings, The (USA) + cheat + description:Start with infinite health - all Vikings + code:7E0FE9:08 + +cartridge sha256:ab3d97c1a3a979e1680a428ec65df54cfb72997bbfe2173292248a4fa8c51ba1 + title:Lost Vikings 2 (USA) + cheat + description:Infinite health - 1st viking + code:7E1037:06 + cheat + description:Infinite health - 2nd viking + code:7E1039:06 + cheat + description:Infinite health - 3rd viking + code:7E103B:06 + +cartridge sha256:8510491f99400115ccf33570269bc4e484fb56370f7ac36f12e73eec19d342da + title:Lucky Luke (Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:7E0526:48 + cheat + description:Infinite health + code:7E059F:04 + cheat + description:Infinite lives + code:7E05A0:09 + cheat + description:Infinite rounds + code:7E05A2:09 + cheat + description:Infinite bombs + code:7E05A3:09 + +cartridge sha256:73731a5a7932965de02a9e98055dcf88b4d17b8f710a6ecfde3e36a1f248773b + title:Lufia & The Fortress of Doom (USA) + cheat + description:Move around caves and world map quicker (except when leaving a vehicle) + code:4DB4-D401 + cheat + description:Infinite HP (hit points) + code:8236-0F34 + cheat + description:Infinite magic points in battle mode + code:823A-0FC4 + cheat + description:No HP lost when walking over swamp ground + code:DDB8-6FD9 + cheat + description:More HP lost when walking over swamp ground + code:D0B8-6FD9 + cheat + description:Cheap bombs - 1 gold each + code:DF30-A718 + cheat + description:Cheap smokeballs - 1 gold each + code:DF3C-0D18 + cheat + description:Immune to all petrifying effects (stone, poison, confused, etc.) + code:6D8F-0DC4 + cheat + description:Shopkeepers don't charge for purchases - some shops only + code:95A8-67A4 + cheat + description:More agility points from speed potion + code:FD34-0448 + cheat + description:More intelligence points from mind potion + code:FD30-0438 + cheat + description:More strength points from great potion + code:FD31-07C8 + cheat + description:Higher max level of magic points from spell potion + code:FD3D-0F18 + cheat + description:Higher max level of hit points from power potion + code:FD33-DDC8 + cheat + description:99 of item in slot 1 + code:7E14F8:63 + cheat + description:99 of item in slot 2 + code:7E14FA:63 + cheat + description:99 of item in slot 3 + code:7E14FC:63 + cheat + description:No random battles + code:7E149E:00 + cheat + description:Slot 1 - Nothing + code:7E14F7:00 + cheat + description:Slot 1 - Knife + code:7E14F7:01 + cheat + description:Slot 1 - Club + code:7E14F7:02 + cheat + description:Slot 1 - Mace + code:7E14F7:03 + cheat + description:Slot 1 - Dagger + code:7E14F7:04 + cheat + description:Slot 1 - Long Knife + code:7E14F7:05 + cheat + description:Slot 1 - Short Sword + code:7E14F7:06 + cheat + description:Slot 1 - Rod + code:7E14F7:07 + cheat + description:Slot 1 - Gladius + code:7E14F7:08 + cheat + description:Slot 1 - Glass Robe + code:7E14F7:09 + cheat + description:Slot 1 - Brone Sword + code:7E14F7:0A + cheat + description:Slot 1 - Staff + code:7E14F7:0B + cheat + description:Slot 1 - Scimitar + code:7E14F7:0C + cheat + description:Slot 1 - Rapier + code:7E14F7:0D + cheat + description:Slot 1 - Long Sword + code:7E14F7:0E + cheat + description:Slot 1 - Long Staff + code:7E14F7:0F + cheat + description:Slot 1 - Axe + code:7E14F7:10 + cheat + description:Slot 1 - Spear + code:7E14F7:11 + cheat + description:Slot 1 - Morning Star + code:7E14F7:12 + cheat + description:Slot 1 - Catwhip + code:7E14F7:13 + cheat + description:Slot 1 - Battle Axe + code:7E14F7:14 + cheat + description:Slot 1 - Hammer Rod + code:7E14F7:15 + cheat + description:Slot 1 - Trident + code:7E14F7:16 + cheat + description:Slot 1 - Silver Rod + code:7E14F7:17 + cheat + description:Slot 1 - Silver Sword + code:7E14F7:18 + cheat + description:Slot 1 - Buster Sword + code:7E14F7:19 + cheat + description:Slot 1 - Zircon Rod + code:7E14F7:1A + cheat + description:Slot 1 - Great Axe + code:7E14F7:1B + cheat + description:Slot 1 - Great Blade + code:7E14F7:1C + cheat + description:Slot 1 - Zircon Axe + code:7E14F7:1D + cheat + description:Slot 1 - Zircon Sword + code:7E14F7:1E + cheat + description:Slot 1 - Broad Sword + code:7E14F7:1F + cheat + description:Slot 1 - Broad Rod + code:7E14F7:20 + cheat + description:Slot 1 - Luck Blade + code:7E14F7:21 + cheat + description:Slot 1 - Gloom Pick + code:7E14F7:22 + cheat + description:Slot 1 - Dual Blade + code:7E14F7:23 + cheat + description:Slot 1 - Dress + code:7E14F7:24 + cheat + description:Slot 1 - Cloth + code:7E14F7:25 + cheat + description:Slot 1 - Cloth Armor + code:7E14F7:26 + cheat + description:Slot 1 - Robe + code:7E14F7:27 + cheat + description:Slot 1 - Tan Armor + code:7E14F7:28 + cheat + description:Slot 1 - Tan Robe + code:7E14F7:29 + cheat + description:Slot 1 - Light Armor + code:7E14F7:2A + cheat + description:Slot 1 - Light Robe + code:7E14F7:2B + cheat + description:Slot 1 - Chain Mail + code:7E14F7:2C + cheat + description:Slot 1 - Chain Cloth + code:7E14F7:2D + cheat + description:Slot 1 - Plate Cloth + code:7E14F7:2E + cheat + description:Slot 1 - Brone Armor + code:7E14F7:2F + cheat + description:Slot 1 - Quilted Silk + code:7E14F7:30 + cheat + description:Slot 1 - Half Mail + code:7E14F7:31 + cheat + description:Slot 1 - Brone Robe + code:7E14F7:32 + cheat + description:Slot 1 - Silver Armor + code:7E14F7:33 + cheat + description:Slot 1 - Silver Robe + code:7E14F7:34 + cheat + description:Slot 1 - Plate Mail + code:7E14F7:35 + cheat + description:Slot 1 - Zircon Robe + code:7E14F7:36 + cheat + description:Slot 1 - Zircon Armor + code:7E14F7:37 + cheat + description:Slot 1 - Clear Silk + code:7E14F7:38 + cheat + description:Slot 1 - Bracelet + code:7E14F7:39 + cheat + description:Slot 1 - Tan Shield + code:7E14F7:3A + cheat + description:Slot 1 - Wood Shield + code:7E14F7:3B + cheat + description:Slot 1 - Buckler + code:7E14F7:3C + cheat + description:Slot 1 - Wood Wrist + code:7E14F7:3D + cheat + description:Slot 1 - Kite Shield + code:7E14F7:3E + cheat + description:Slot 1 - Round Shield + code:7E14F7:3F + cheat + description:Slot 1 - Round Wrist + code:7E14F7:40 + cheat + description:Slot 1 - Brone Shield + code:7E14F7:41 + cheat + description:Slot 1 - Tower Shield + code:7E14F7:42 + cheat + description:Slot 1 - Large Shield + code:7E14F7:43 + cheat + description:Slot 1 - Silver Wrist + code:7E14F7:44 + cheat + description:Slot 1 - Silver Plate + code:7E14F7:45 + cheat + description:Slot 1 - Zircon Wrist + code:7E14F7:46 + cheat + description:Slot 1 - Zircon Plate + code:7E14F7:47 + cheat + description:Slot 1 - Cloth Helm + code:7E14F7:48 + cheat + description:Slot 1 - Tan Helm + code:7E14F7:49 + cheat + description:Slot 1 - Hair Band + code:7E14F7:4A + cheat + description:Slot 1 - Wood Helm + code:7E14F7:4B + cheat + description:Slot 1 - Glass Cap + code:7E14F7:4C + cheat + description:Slot 1 - Brone Helm + code:7E14F7:4D + cheat + description:Slot 1 - Red Beret + code:7E14F7:4E + cheat + description:Slot 1 - Iron Helm + code:7E14F7:4F + cheat + description:Slot 1 - Plate Cap + code:7E14F7:50 + cheat + description:Slot 1 - Plate Helm + code:7E14F7:51 + cheat + description:Slot 1 - Glass Beret + code:7E14F7:52 + cheat + description:Slot 1 - Silver Helm + code:7E14F7:53 + cheat + description:Slot 1 - Sakret + code:7E14F7:54 + cheat + description:Slot 1 - Zircon Beret + code:7E14F7:55 + cheat + description:Slot 1 - Zircon Helm + code:7E14F7:56 + cheat + description:Slot 1 - Sandal + code:7E14F7:57 + cheat + description:Slot 1 - Cloth Shoes + code:7E14F7:58 + cheat + description:Slot 1 - Tan Shoes + code:7E14F7:59 + cheat + description:Slot 1 - Spike Shoes + code:7E14F7:5A + cheat + description:Slot 1 - Heeled Shoes + code:7E14F7:5B + cheat + description:Slot 1 - Wind Shoes + code:7E14F7:5C + cheat + description:Slot 1 - Wind Heels + code:7E14F7:5D + cheat + description:Slot 1 - Knife Shoes + code:7E14F7:5E + cheat + description:Slot 1 - Needle Heels + code:7E14F7:5F + cheat + description:Slot 1 - Sonic Shoes + code:7E14F7:60 + cheat + description:Slot 1 - Sonic Heels + code:7E14F7:61 + cheat + description:Slot 1 - Sword Shoes + code:7E14F7:62 + cheat + description:Slot 1 - Cat Heels + code:7E14F7:63 + cheat + description:Slot 1 - Mach Shoes + code:7E14F7:64 + cheat + description:Slot 1 - Mach Heels + code:7E14F7:65 + cheat + description:Slot 1 - Power Ring + code:7E14F7:66 + cheat + description:Slot 1 - HiPower Ring + code:7E14F7:67 + cheat + description:Slot 1 - Daze Ring + code:7E14F7:68 + cheat + description:Slot 1 - Hi Daze Ring + code:7E14F7:69 + cheat + description:Slot 1 - Mind Ring + code:7E14F7:6A + cheat + description:Slot 1 - Sonic Ring + code:7E14F7:6B + cheat + description:Slot 1 - Mach Ring + code:7E14F7:6C + cheat + description:Slot 1 - Undead Ring + code:7E14F7:6D + cheat + description:Slot 1 - Ghost Ring + code:7E14F7:6E + cheat + description:Slot 1 - Dragon Ring + code:7E14F7:6F + cheat + description:Slot 1 - Sea Ring + code:7E14F7:70 + cheat + description:Slot 1 - Fly Ring + code:7E14F7:71 + cheat + description:Slot 1 - Water Ring + code:7E14F7:72 + cheat + description:Slot 1 - Fire Ring + code:7E14F7:73 + cheat + description:Slot 1 - Ice Ring + code:7E14F7:74 + cheat + description:Slot 1 - Electro Ring + code:7E14F7:75 + cheat + description:Slot 1 - Flash Ring + code:7E14F7:76 + cheat + description:Slot 1 - Flame Ring + code:7E14F7:77 + cheat + description:Slot 1 - Water Ring + code:7E14F7:78 + cheat + description:Slot 1 - Blast Ring + code:7E14F7:79 + cheat + description:Slot 1 - Frost Ring + code:7E14F7:7A + cheat + description:Slot 1 - Might Armor + code:7E14F7:7B + cheat + description:Slot 1 - Might Shield + code:7E14F7:7C + cheat + description:Slot 1 - Might Helmet + code:7E14F7:7D + cheat + description:Slot 1 - Gloom Ring + code:7E14F7:7E + cheat + description:Slot 1 - Gloom Voice + code:7E14F7:7F + cheat + description:Slot 1 - Dummy (?) + code:7E14F7:80 + cheat + description:Slot 1 - Brone Breast + code:7E14F7:81 + cheat + description:Slot 1 - Carbo Sword + code:7E14F7:82 + cheat + description:Slot 1 - Carbo Plate + code:7E14F7:83 + cheat + description:Slot 1 - Carbo Shield + code:7E14F7:84 + cheat + description:Slot 1 - Carbo Helm + code:7E14F7:85 + cheat + description:Slot 1 - Carbo Cap + code:7E14F7:86 + cheat + description:Slot 1 - Gloom Guard + code:7E14F7:87 + cheat + description:Slot 1 - Diamond Ring + code:7E14F7:88 + cheat + description:Slot 1 - Engage Ring + code:7E14F7:89 + cheat + description:Slot 1 - Monster Ring + code:7E14F7:8A + cheat + description:Slot 1 - Blue Ring + code:7E14F7:8B + cheat + description:Slot 1 - Yellow Ring + code:7E14F7:8C + cheat + description:Slot 1 - Red Ring + code:7E14F7:8D + cheat + description:Slot 1 - Purple Ring + code:7E14F7:8E + cheat + description:Slot 1 - Green Ring + code:7E14F7:8F + cheat + description:Slot 1 - White Ring + code:7E14F7:90 + cheat + description:Slot 1 - Black Ring + code:7E14F7:91 + cheat + description:Slot 1 - Heavy Ring + code:7E14F7:92 + cheat + description:Slot 1 - Wave Ring + code:7E14F7:93 + cheat + description:Slot 1 - Potion + code:7E14F7:94 + cheat + description:Slot 1 - Hi Potion + code:7E14F7:95 + cheat + description:Slot 1 - Ex Potion + code:7E14F7:96 + cheat + description:Slot 1 - Hi Magic + code:7E14F7:97 + cheat + description:Slot 1 - Ex Magic + code:7E14F7:98 + cheat + description:Slot 1 - Antidote + code:7E14F7:99 + cheat + description:Slot 1 - Sweet Water + code:7E14F7:9A + cheat + description:Slot 1 - Foul Water + code:7E14F7:9B + cheat + description:Slot 1 - Awaken + code:7E14F7:9C + cheat + description:Slot 1 - Stone Cure + code:7E14F7:9D + cheat + description:Slot 1 - Mystery Pin + code:7E14F7:9E + cheat + description:Slot 1 - Shriek + code:7E14F7:9F + cheat + description:Slot 1 - Swing Wing + code:7E14F7:A0 + cheat + description:Slot 1 - Magic Guard + code:7E14F7:A1 + cheat + description:Slot 1 - Power Gourd + code:7E14F7:A2 + cheat + description:Slot 1 - Mind Gourd + code:7E14F7:A3 + cheat + description:Slot 1 - Power Potion + code:7E14F7:A4 + cheat + description:Slot 1 - Spell Potion + code:7E14F7:A5 + cheat + description:Slot 1 - Speed Potion + code:7E14F7:A6 + cheat + description:Slot 1 - Mind Potion + code:7E14F7:A7 + cheat + description:Slot 1 - Great Potion + code:7E14F7:A8 + cheat + description:Slot 1 - Float + code:7E14F7:A9 + cheat + description:Slot 1 - Smoke Ball + code:7E14F7:AA + cheat + description:Slot 1 - Arrow + code:7E14F7:AB + cheat + description:Slot 1 - Mid Arrow + code:7E14F7:AC + cheat + description:Slot 1 - Big Arrow + code:7E14F7:AD + cheat + description:Slot 1 - Arrows + code:7E14F7:AE + cheat + description:Slot 1 - Hi Arrows + code:7E14F7:AF + cheat + description:Slot 1 - Ex Arrows + code:7E14F7:B0 + cheat + description:Slot 1 - Dragon Arrow + code:7E14F7:B1 + cheat + description:Slot 1 - Sleep Arrow + code:7E14F7:B2 + cheat + description:Slot 1 - Puzzle Arrow + code:7E14F7:B3 + cheat + description:Slot 1 - Stun Arrow + code:7E14F7:B4 + cheat + description:Slot 1 - Gloom Arrow + code:7E14F7:B5 + cheat + description:Slot 1 - Bomb + code:7E14F7:B6 + cheat + description:Slot 1 - Hi Bomb + code:7E14F7:B7 + cheat + description:Slot 1 - Ex Bomb + code:7E14F7:B8 + cheat + description:Slot 1 - Miracle + code:7E14F7:B9 + cheat + description:Slot 1 - Revive + code:7E14F7:BA + cheat + description:Slot 1 - Pear Cider + code:7E14F7:BB + cheat + description:Slot 1 - Sour Cider + code:7E14F7:BC + cheat + description:Slot 1 - Lime Cider + code:7E14F7:BD + cheat + description:Slot 1 - Plum Cider + code:7E14F7:BE + cheat + description:Slot 1 - Apple Cider + code:7E14F7:BF + cheat + description:Slot 1 - Hair Band + code:7E14F7:C0 + cheat + description:Slot 1 - Brooch + code:7E14F7:C1 + cheat + description:Slot 1 - Earring + code:7E14F7:C2 + cheat + description:Slot 1 - Necklace + code:7E14F7:C3 + cheat + description:Slot 1 - Stuffed Bear + code:7E14F7:C4 + cheat + description:Slot 1 - Stuffed Dog + code:7E14F7:C5 + cheat + description:Slot 1 - Stuffed Pig + code:7E14F7:C6 + cheat + description:Slot 1 - Emerald + code:7E14F7:C7 + cheat + description:Slot 1 - Opal + code:7E14F7:C8 + cheat + description:Slot 1 - Goblet + code:7E14F7:C9 + cheat + description:Slot 1 - Ear Tip + code:7E14F7:CA + cheat + description:Slot 1 - Empty Bottle + code:7E14F7:CB + cheat + description:Slot 1 - Gown + code:7E14F7:CC + cheat + description:Slot 1 - Ribbon + code:7E14F7:CD + cheat + description:Slot 1 - Fry Pan + code:7E14F7:CE + cheat + description:Slot 1 - Small Knife + code:7E14F7:CF + cheat + description:Slot 1 - Pot + code:7E14F7:D0 + cheat + description:Slot 1 - Chop Block + code:7E14F7:D1 + cheat + description:Slot 1 - Apron + code:7E14F7:D2 + cheat + description:Slot 1 - Dragon Egg + code:7E14F7:D3 + cheat + description:Slot 1 - Crown + code:7E14F7:D4 + cheat + description:Slot 1 - Secret Map + code:7E14F7:D5 + cheat + description:Slot 1 - Miracle Gem + code:7E14F7:D6 + cheat + description:Slot 1 - Silver Wick + code:7E14F7:D7 + cheat + description:Slot 1 - Royal Statue + code:7E14F7:D8 + cheat + description:Slot 1 - Silver Tarot + code:7E14F7:D9 + cheat + description:Slot 1 - Golden Pawn + code:7E14F7:DA + cheat + description:Slot 1 - Crown Jewels + code:7E14F7:DB + cheat + description:Slot 1 - Wind Flute + code:7E14F7:DC + cheat + description:Slot 1 - Escape + code:7E14F7:DD + cheat + description:Slot 1 - Magic Jar + code:7E14F7:DE + cheat + description:Slot 1 - Dragon Tooth + code:7E14F7:DF + cheat + description:Slot 1 - Grilled Newt + code:7E14F7:E0 + cheat + description:Slot 1 - Poison Pin + code:7E14F7:E1 + cheat + description:Slot 1 - Might Sword + code:7E14F7:E2 + cheat + description:Slot 1 - Straw Doll + code:7E14F7:E3 + cheat + description:Slot 1 - Long Nail + code:7E14F7:E4 + cheat + description:Slot 1 - Bomb + code:7E14F7:E5 + cheat + description:Slot 1 - Alumina + code:7E14F7:E6 + cheat + description:Slot 1 - Power Oil + code:7E14F7:E7 + cheat + description:Slot 1 - Elven Bow + code:7E14F7:E8 + cheat + description:Slot 1 - Artea's Bow + code:7E14F7:E9 + cheat + description:Slot 1 - Might Bow + code:7E14F7:EA + cheat + description:Slot 1 - Dummy (?) + code:7E14F7:EB + cheat + description:Slot 1 - Dummy (?) + code:7E14F7:EC + cheat + description:Slot 1 - Dummy (?) + code:7E14F7:ED + cheat + description:Slot 1 - Dummy (?) + code:7E14F7:EE + cheat + description:Slot 1 - Free Door + code:7E14F7:EF + cheat + description:Slot 1 - Sheran Key + code:7E14F7:F0 + cheat + description:Slot 1 - Letter + code:7E14F7:F1 + cheat + description:Slot 1 - Dais Key + code:7E14F7:F2 + cheat + description:Slot 1 - Shrine Key + code:7E14F7:F3 + cheat + description:Slot 1 - Pirate Key + code:7E14F7:F4 + cheat + description:Slot 1 - Light Key + code:7E14F7:F5 + cheat + description:Slot 1 - Oil Key + code:7E14F7:F6 + cheat + description:Slot 1 - Green Jade + code:7E14F7:F7 + cheat + description:Slot 1 - Red Sapphire + code:7E14F7:F8 + cheat + description:Slot 1 - Blue Jade + code:7E14F7:F9 + cheat + description:Slot 1 - Purple Newt + code:7E14F7:FA + cheat + description:Slot 1 - Glasdar Key + code:7E14F7:FB + cheat + description:Slot 1 - Magic Flavor + code:7E14F7:FC + cheat + description:Slot 1 - Fairy Kiss + code:7E14F7:FD + cheat + description:Slot 2 - Nothing + code:7E14F9:00 + cheat + description:Slot 2 - Knife + code:7E14F9:01 + cheat + description:Slot 2 - Club + code:7E14F9:02 + cheat + description:Slot 2 - Mace + code:7E14F9:03 + cheat + description:Slot 2 - Dagger + code:7E14F9:04 + cheat + description:Slot 2 - Long Knife + code:7E14F9:05 + cheat + description:Slot 2 - Short Sword + code:7E14F9:06 + cheat + description:Slot 2 - Rod + code:7E14F9:07 + cheat + description:Slot 2 - Gladius + code:7E14F9:08 + cheat + description:Slot 2 - Glass Robe + code:7E14F9:09 + cheat + description:Slot 2 - Brone Sword + code:7E14F9:0A + cheat + description:Slot 2 - Staff + code:7E14F9:0B + cheat + description:Slot 2 - Scimitar + code:7E14F9:0C + cheat + description:Slot 2 - Rapier + code:7E14F9:0D + cheat + description:Slot 2 - Long Sword + code:7E14F9:0E + cheat + description:Slot 2 - Long Staff + code:7E14F9:0F + cheat + description:Slot 2 - Axe + code:7E14F9:10 + cheat + description:Slot 2 - Spear + code:7E14F9:11 + cheat + description:Slot 2 - Morning Star + code:7E14F9:12 + cheat + description:Slot 2 - Catwhip + code:7E14F9:13 + cheat + description:Slot 2 - Battle Axe + code:7E14F9:14 + cheat + description:Slot 2 - Hammer Rod + code:7E14F9:15 + cheat + description:Slot 2 - Trident + code:7E14F9:16 + cheat + description:Slot 2 - Silver Rod + code:7E14F9:17 + cheat + description:Slot 2 - Silver Sword + code:7E14F9:18 + cheat + description:Slot 2 - Buster Sword + code:7E14F9:19 + cheat + description:Slot 2 - Zircon Rod + code:7E14F9:1A + cheat + description:Slot 2 - Great Axe + code:7E14F9:1B + cheat + description:Slot 2 - Great Blade + code:7E14F9:1C + cheat + description:Slot 2 - Zircon Axe + code:7E14F9:1D + cheat + description:Slot 2 - Zircon Sword + code:7E14F9:1E + cheat + description:Slot 2 - Broad Sword + code:7E14F9:1F + cheat + description:Slot 2 - Broad Rod + code:7E14F9:20 + cheat + description:Slot 2 - Luck Blade + code:7E14F9:21 + cheat + description:Slot 2 - Gloom Pick + code:7E14F9:22 + cheat + description:Slot 2 - Dual Blade + code:7E14F9:23 + cheat + description:Slot 2 - Dress + code:7E14F9:24 + cheat + description:Slot 2 - Cloth + code:7E14F9:25 + cheat + description:Slot 2 - Cloth Armor + code:7E14F9:26 + cheat + description:Slot 2 - Robe + code:7E14F9:27 + cheat + description:Slot 2 - Tan Armor + code:7E14F9:28 + cheat + description:Slot 2 - Tan Robe + code:7E14F9:29 + cheat + description:Slot 2 - Light Armor + code:7E14F9:2A + cheat + description:Slot 2 - Light Robe + code:7E14F9:2B + cheat + description:Slot 2 - Chain Mail + code:7E14F9:2C + cheat + description:Slot 2 - Chain Cloth + code:7E14F9:2D + cheat + description:Slot 2 - Plate Cloth + code:7E14F9:2E + cheat + description:Slot 2 - Brone Armor + code:7E14F9:2F + cheat + description:Slot 2 - Quilted Silk + code:7E14F9:30 + cheat + description:Slot 2 - Half Mail + code:7E14F9:31 + cheat + description:Slot 2 - Brone Robe + code:7E14F9:32 + cheat + description:Slot 2 - Silver Armor + code:7E14F9:33 + cheat + description:Slot 2 - Silver Robe + code:7E14F9:34 + cheat + description:Slot 2 - Plate Mail + code:7E14F9:35 + cheat + description:Slot 2 - Zircon Robe + code:7E14F9:36 + cheat + description:Slot 2 - Zircon Armor + code:7E14F9:37 + cheat + description:Slot 2 - Clear Silk + code:7E14F9:38 + cheat + description:Slot 2 - Bracelet + code:7E14F9:39 + cheat + description:Slot 2 - Tan Shield + code:7E14F9:3A + cheat + description:Slot 2 - Wood Shield + code:7E14F9:3B + cheat + description:Slot 2 - Buckler + code:7E14F9:3C + cheat + description:Slot 2 - Wood Wrist + code:7E14F9:3D + cheat + description:Slot 2 - Kite Shield + code:7E14F9:3E + cheat + description:Slot 2 - Round Shield + code:7E14F9:3F + cheat + description:Slot 2 - Round Wrist + code:7E14F9:40 + cheat + description:Slot 2 - Brone Shield + code:7E14F9:41 + cheat + description:Slot 2 - Tower Shield + code:7E14F9:42 + cheat + description:Slot 2 - Large Shield + code:7E14F9:43 + cheat + description:Slot 2 - Silver Wrist + code:7E14F9:44 + cheat + description:Slot 2 - Silver Plate + code:7E14F9:45 + cheat + description:Slot 2 - Zircon Wrist + code:7E14F9:46 + cheat + description:Slot 2 - Zircon Plate + code:7E14F9:47 + cheat + description:Slot 2 - Cloth Helm + code:7E14F9:48 + cheat + description:Slot 2 - Tan Helm + code:7E14F9:49 + cheat + description:Slot 2 - Hair Band + code:7E14F9:4A + cheat + description:Slot 2 - Wood Helm + code:7E14F9:4B + cheat + description:Slot 2 - Glass Cap + code:7E14F9:4C + cheat + description:Slot 2 - Brone Helm + code:7E14F9:4D + cheat + description:Slot 2 - Red Beret + code:7E14F9:4E + cheat + description:Slot 2 - Iron Helm + code:7E14F9:4F + cheat + description:Slot 2 - Plate Cap + code:7E14F9:50 + cheat + description:Slot 2 - Plate Helm + code:7E14F9:51 + cheat + description:Slot 2 - Glass Beret + code:7E14F9:52 + cheat + description:Slot 2 - Silver Helm + code:7E14F9:53 + cheat + description:Slot 2 - Sakret + code:7E14F9:54 + cheat + description:Slot 2 - Zircon Beret + code:7E14F9:55 + cheat + description:Slot 2 - Zircon Helm + code:7E14F9:56 + cheat + description:Slot 2 - Sandal + code:7E14F9:57 + cheat + description:Slot 2 - Cloth Shoes + code:7E14F9:58 + cheat + description:Slot 2 - Tan Shoes + code:7E14F9:59 + cheat + description:Slot 2 - Spike Shoes + code:7E14F9:5A + cheat + description:Slot 2 - Heeled Shoes + code:7E14F9:5B + cheat + description:Slot 2 - Wind Shoes + code:7E14F9:5C + cheat + description:Slot 2 - Wind Heels + code:7E14F9:5D + cheat + description:Slot 2 - Knife Shoes + code:7E14F9:5E + cheat + description:Slot 2 - Needle Heels + code:7E14F9:5F + cheat + description:Slot 2 - Sonic Shoes + code:7E14F9:60 + cheat + description:Slot 2 - Sonic Heels + code:7E14F9:61 + cheat + description:Slot 2 - Sword Shoes + code:7E14F9:62 + cheat + description:Slot 2 - Cat Heels + code:7E14F9:63 + cheat + description:Slot 2 - Mach Shoes + code:7E14F9:64 + cheat + description:Slot 2 - Mach Heels + code:7E14F9:65 + cheat + description:Slot 2 - Power Ring + code:7E14F9:66 + cheat + description:Slot 2 - HiPower Ring + code:7E14F9:67 + cheat + description:Slot 2 - Daze Ring + code:7E14F9:68 + cheat + description:Slot 2 - Hi Daze Ring + code:7E14F9:69 + cheat + description:Slot 2 - Mind Ring + code:7E14F9:6A + cheat + description:Slot 2 - Sonic Ring + code:7E14F9:6B + cheat + description:Slot 2 - Mach Ring + code:7E14F9:6C + cheat + description:Slot 2 - Undead Ring + code:7E14F9:6D + cheat + description:Slot 2 - Ghost Ring + code:7E14F9:6E + cheat + description:Slot 2 - Dragon Ring + code:7E14F9:6F + cheat + description:Slot 2 - Sea Ring + code:7E14F9:70 + cheat + description:Slot 2 - Fly Ring + code:7E14F9:71 + cheat + description:Slot 2 - Water Ring + code:7E14F9:72 + cheat + description:Slot 2 - Fire Ring + code:7E14F9:73 + cheat + description:Slot 2 - Ice Ring + code:7E14F9:74 + cheat + description:Slot 2 - Electro Ring + code:7E14F9:75 + cheat + description:Slot 2 - Flash Ring + code:7E14F9:76 + cheat + description:Slot 2 - Flame Ring + code:7E14F9:77 + cheat + description:Slot 2 - Water Ring + code:7E14F9:78 + cheat + description:Slot 2 - Blast Ring + code:7E14F9:79 + cheat + description:Slot 2 - Frost Ring + code:7E14F9:7A + cheat + description:Slot 2 - Might Armor + code:7E14F9:7B + cheat + description:Slot 2 - Might Shield + code:7E14F9:7C + cheat + description:Slot 2 - Might Helmet + code:7E14F9:7D + cheat + description:Slot 2 - Gloom Ring + code:7E14F9:7E + cheat + description:Slot 2 - Gloom Voice + code:7E14F9:7F + cheat + description:Slot 2 - Dummy (?) + code:7E14F9:80 + cheat + description:Slot 2 - Brone Breast + code:7E14F9:81 + cheat + description:Slot 2 - Carbo Sword + code:7E14F9:82 + cheat + description:Slot 2 - Carbo Plate + code:7E14F9:83 + cheat + description:Slot 2 - Carbo Shield + code:7E14F9:84 + cheat + description:Slot 2 - Carbo Helm + code:7E14F9:85 + cheat + description:Slot 2 - Carbo Cap + code:7E14F9:86 + cheat + description:Slot 2 - Gloom Guard + code:7E14F9:87 + cheat + description:Slot 2 - Diamond Ring + code:7E14F9:88 + cheat + description:Slot 2 - Engage Ring + code:7E14F9:89 + cheat + description:Slot 2 - Monster Ring + code:7E14F9:8A + cheat + description:Slot 2 - Blue Ring + code:7E14F9:8B + cheat + description:Slot 2 - Yellow Ring + code:7E14F9:8C + cheat + description:Slot 2 - Red Ring + code:7E14F9:8D + cheat + description:Slot 2 - Purple Ring + code:7E14F9:8E + cheat + description:Slot 2 - Green Ring + code:7E14F9:8F + cheat + description:Slot 2 - White Ring + code:7E14F9:90 + cheat + description:Slot 2 - Black Ring + code:7E14F9:91 + cheat + description:Slot 2 - Heavy Ring + code:7E14F9:92 + cheat + description:Slot 2 - Wave Ring + code:7E14F9:93 + cheat + description:Slot 2 - Potion + code:7E14F9:94 + cheat + description:Slot 2 - Hi Potion + code:7E14F9:95 + cheat + description:Slot 2 - Ex Potion + code:7E14F9:96 + cheat + description:Slot 2 - Hi Magic + code:7E14F9:97 + cheat + description:Slot 2 - Ex Magic + code:7E14F9:98 + cheat + description:Slot 2 - Antidote + code:7E14F9:99 + cheat + description:Slot 2 - Sweet Water + code:7E14F9:9A + cheat + description:Slot 2 - Foul Water + code:7E14F9:9B + cheat + description:Slot 2 - Awaken + code:7E14F9:9C + cheat + description:Slot 2 - Stone Cure + code:7E14F9:9D + cheat + description:Slot 2 - Mystery Pin + code:7E14F9:9E + cheat + description:Slot 2 - Shriek + code:7E14F9:9F + cheat + description:Slot 2 - Swing Wing + code:7E14F9:A0 + cheat + description:Slot 2 - Magic Guard + code:7E14F9:A1 + cheat + description:Slot 2 - Power Gourd + code:7E14F9:A2 + cheat + description:Slot 2 - Mind Gourd + code:7E14F9:A3 + cheat + description:Slot 2 - Power Potion + code:7E14F9:A4 + cheat + description:Slot 2 - Spell Potion + code:7E14F9:A5 + cheat + description:Slot 2 - Speed Potion + code:7E14F9:A6 + cheat + description:Slot 2 - Mind Potion + code:7E14F9:A7 + cheat + description:Slot 2 - Great Potion + code:7E14F9:A8 + cheat + description:Slot 2 - Float + code:7E14F9:A9 + cheat + description:Slot 2 - Smoke Ball + code:7E14F9:AA + cheat + description:Slot 2 - Arrow + code:7E14F9:AB + cheat + description:Slot 2 - Mid Arrow + code:7E14F9:AC + cheat + description:Slot 2 - Big Arrow + code:7E14F9:AD + cheat + description:Slot 2 - Arrows + code:7E14F9:AE + cheat + description:Slot 2 - Hi Arrows + code:7E14F9:AF + cheat + description:Slot 2 - Ex Arrows + code:7E14F9:B0 + cheat + description:Slot 2 - Dragon Arrow + code:7E14F9:B1 + cheat + description:Slot 2 - Sleep Arrow + code:7E14F9:B2 + cheat + description:Slot 2 - Puzzle Arrow + code:7E14F9:B3 + cheat + description:Slot 2 - Stun Arrow + code:7E14F9:B4 + cheat + description:Slot 2 - Gloom Arrow + code:7E14F9:B5 + cheat + description:Slot 2 - Bomb + code:7E14F9:B6 + cheat + description:Slot 2 - Hi Bomb + code:7E14F9:B7 + cheat + description:Slot 2 - Ex Bomb + code:7E14F9:B8 + cheat + description:Slot 2 - Miracle + code:7E14F9:B9 + cheat + description:Slot 2 - Revive + code:7E14F9:BA + cheat + description:Slot 2 - Pear Cider + code:7E14F9:BB + cheat + description:Slot 2 - Sour Cider + code:7E14F9:BC + cheat + description:Slot 2 - Lime Cider + code:7E14F9:BD + cheat + description:Slot 2 - Plum Cider + code:7E14F9:BE + cheat + description:Slot 2 - Apple Cider + code:7E14F9:BF + cheat + description:Slot 2 - Hair Band + code:7E14F9:C0 + cheat + description:Slot 2 - Brooch + code:7E14F9:C1 + cheat + description:Slot 2 - Earring + code:7E14F9:C2 + cheat + description:Slot 2 - Necklace + code:7E14F9:C3 + cheat + description:Slot 2 - Stuffed Bear + code:7E14F9:C4 + cheat + description:Slot 2 - Stuffed Dog + code:7E14F9:C5 + cheat + description:Slot 2 - Stuffed Pig + code:7E14F9:C6 + cheat + description:Slot 2 - Emerald + code:7E14F9:C7 + cheat + description:Slot 2 - Opal + code:7E14F9:C8 + cheat + description:Slot 2 - Goblet + code:7E14F9:C9 + cheat + description:Slot 2 - Ear Tip + code:7E14F9:CA + cheat + description:Slot 2 - Empty Bottle + code:7E14F9:CB + cheat + description:Slot 2 - Gown + code:7E14F9:CC + cheat + description:Slot 2 - Ribbon + code:7E14F9:CD + cheat + description:Slot 2 - Fry Pan + code:7E14F9:CE + cheat + description:Slot 2 - Small Knife + code:7E14F9:CF + cheat + description:Slot 2 - Pot + code:7E14F9:D0 + cheat + description:Slot 2 - Chop Block + code:7E14F9:D1 + cheat + description:Slot 2 - Apron + code:7E14F9:D2 + cheat + description:Slot 2 - Dragon Egg + code:7E14F9:D3 + cheat + description:Slot 2 - Crown + code:7E14F9:D4 + cheat + description:Slot 2 - Secret Map + code:7E14F9:D5 + cheat + description:Slot 2 - Miracle Gem + code:7E14F9:D6 + cheat + description:Slot 2 - Silver Wick + code:7E14F9:D7 + cheat + description:Slot 2 - Royal Statue + code:7E14F9:D8 + cheat + description:Slot 2 - Silver Tarot + code:7E14F9:D9 + cheat + description:Slot 2 - Golden Pawn + code:7E14F9:DA + cheat + description:Slot 2 - Crown Jewels + code:7E14F9:DB + cheat + description:Slot 2 - Wind Flute + code:7E14F9:DC + cheat + description:Slot 2 - Escape + code:7E14F9:DD + cheat + description:Slot 2 - Magic Jar + code:7E14F9:DE + cheat + description:Slot 2 - Dragon Tooth + code:7E14F9:DF + cheat + description:Slot 2 - Grilled Newt + code:7E14F9:E0 + cheat + description:Slot 2 - Poison Pin + code:7E14F9:E1 + cheat + description:Slot 2 - Might Sword + code:7E14F9:E2 + cheat + description:Slot 2 - Straw Doll + code:7E14F9:E3 + cheat + description:Slot 2 - Long Nail + code:7E14F9:E4 + cheat + description:Slot 2 - Bomb + code:7E14F9:E5 + cheat + description:Slot 2 - Alumina + code:7E14F9:E6 + cheat + description:Slot 2 - Power Oil + code:7E14F9:E7 + cheat + description:Slot 2 - Elven Bow + code:7E14F9:E8 + cheat + description:Slot 2 - Artea's Bow + code:7E14F9:E9 + cheat + description:Slot 2 - Might Bow + code:7E14F9:EA + cheat + description:Slot 2 - Dummy (?) + code:7E14F9:EB + cheat + description:Slot 2 - Dummy (?) + code:7E14F9:EC + cheat + description:Slot 2 - Dummy (?) + code:7E14F9:ED + cheat + description:Slot 2 - Dummy (?) + code:7E14F9:EE + cheat + description:Slot 2 - Free Door + code:7E14F9:EF + cheat + description:Slot 2 - Sheran Key + code:7E14F9:F0 + cheat + description:Slot 2 - Letter + code:7E14F9:F1 + cheat + description:Slot 2 - Dais Key + code:7E14F9:F2 + cheat + description:Slot 2 - Shrine Key + code:7E14F9:F3 + cheat + description:Slot 2 - Pirate Key + code:7E14F9:F4 + cheat + description:Slot 2 - Light Key + code:7E14F9:F5 + cheat + description:Slot 2 - Oil Key + code:7E14F9:F6 + cheat + description:Slot 2 - Green Jade + code:7E14F9:F9 + cheat + description:Slot 2 - Red Sapphire + code:7E14F9:F8 + cheat + description:Slot 2 - Blue Jade + code:7E14F9:F9 + cheat + description:Slot 2 - Purple Newt + code:7E14F9:FA + cheat + description:Slot 2 - Glasdar Key + code:7E14F9:FB + cheat + description:Slot 2 - Magic Flavor + code:7E14F9:FC + cheat + description:Slot 2 - Fairy Kiss + code:7E14F9:FD + cheat + description:Slot 3 - Nothing + code:7E14FB:00 + cheat + description:Slot 3 - Knife + code:7E14FB:01 + cheat + description:Slot 3 - Club + code:7E14FB:02 + cheat + description:Slot 3 - Mace + code:7E14FB:03 + cheat + description:Slot 3 - Dagger + code:7E14FB:04 + cheat + description:Slot 3 - Long Knife + code:7E14FB:05 + cheat + description:Slot 3 - Short Sword + code:7E14FB:06 + cheat + description:Slot 3 - Rod + code:7E14FB:07 + cheat + description:Slot 3 - Gladius + code:7E14FB:08 + cheat + description:Slot 3 - Glass Robe + code:7E14FB:09 + cheat + description:Slot 3 - Brone Sword + code:7E14FB:0A + cheat + description:Slot 3 - Staff + code:7E14FB:0B + cheat + description:Slot 3 - Scimitar + code:7E14FB:0C + cheat + description:Slot 3 - Rapier + code:7E14FB:0D + cheat + description:Slot 3 - Long Sword + code:7E14FB:0E + cheat + description:Slot 3 - Long Staff + code:7E14FB:0F + cheat + description:Slot 3 - Axe + code:7E14FB:10 + cheat + description:Slot 3 - Spear + code:7E14FB:11 + cheat + description:Slot 3 - Morning Star + code:7E14FB:12 + cheat + description:Slot 3 - Catwhip + code:7E14FB:13 + cheat + description:Slot 3 - Battle Axe + code:7E14FB:14 + cheat + description:Slot 3 - Hammer Rod + code:7E14FB:15 + cheat + description:Slot 3 - Trident + code:7E14FB:16 + cheat + description:Slot 3 - Silver Rod + code:7E14FB:17 + cheat + description:Slot 3 - Silver Sword + code:7E14FB:18 + cheat + description:Slot 3 - Buster Sword + code:7E14FB:19 + cheat + description:Slot 3 - Zircon Rod + code:7E14FB:1A + cheat + description:Slot 3 - Great Axe + code:7E14FB:1B + cheat + description:Slot 3 - Great Blade + code:7E14FB:1C + cheat + description:Slot 3 - Zircon Axe + code:7E14FB:1D + cheat + description:Slot 3 - Zircon Sword + code:7E14FB:1E + cheat + description:Slot 3 - Broad Sword + code:7E14FB:1F + cheat + description:Slot 3 - Broad Rod + code:7E14FB:20 + cheat + description:Slot 3 - Luck Blade + code:7E14FB:21 + cheat + description:Slot 3 - Gloom Pick + code:7E14FB:22 + cheat + description:Slot 3 - Dual Blade + code:7E14FB:23 + cheat + description:Slot 3 - Dress + code:7E14FB:24 + cheat + description:Slot 3 - Cloth + code:7E14FB:25 + cheat + description:Slot 3 - Cloth Armor + code:7E14FB:26 + cheat + description:Slot 3 - Robe + code:7E14FB:27 + cheat + description:Slot 3 - Tan Armor + code:7E14FB:28 + cheat + description:Slot 3 - Tan Robe + code:7E14FB:29 + cheat + description:Slot 3 - Light Armor + code:7E14FB:2A + cheat + description:Slot 3 - Light Robe + code:7E14FB:2B + cheat + description:Slot 3 - Chain Mail + code:7E14FB:2C + cheat + description:Slot 3 - Chain Cloth + code:7E14FB:2D + cheat + description:Slot 3 - Plate Cloth + code:7E14FB:2E + cheat + description:Slot 3 - Brone Armor + code:7E14FB:2F + cheat + description:Slot 3 - Quilted Silk + code:7E14FB:30 + cheat + description:Slot 3 - Half Mail + code:7E14FB:31 + cheat + description:Slot 3 - Brone Robe + code:7E14FB:32 + cheat + description:Slot 3 - Silver Armor + code:7E14FB:33 + cheat + description:Slot 3 - Silver Robe + code:7E14FB:34 + cheat + description:Slot 3 - Plate Mail + code:7E14FB:35 + cheat + description:Slot 3 - Zircon Robe + code:7E14FB:36 + cheat + description:Slot 3 - Zircon Armor + code:7E14FB:37 + cheat + description:Slot 3 - Clear Silk + code:7E14FB:38 + cheat + description:Slot 3 - Bracelet + code:7E14FB:39 + cheat + description:Slot 3 - Tan Shield + code:7E14FB:3A + cheat + description:Slot 3 - Wood Shield + code:7E14FB:3B + cheat + description:Slot 3 - Buckler + code:7E14FB:3C + cheat + description:Slot 3 - Wood Wrist + code:7E14FB:3D + cheat + description:Slot 3 - Kite Shield + code:7E14FB:3E + cheat + description:Slot 3 - Round Shield + code:7E14FB:3F + cheat + description:Slot 3 - Round Wrist + code:7E14FB:40 + cheat + description:Slot 3 - Brone Shield + code:7E14FB:41 + cheat + description:Slot 3 - Tower Shield + code:7E14FB:42 + cheat + description:Slot 3 - Large Shield + code:7E14FB:43 + cheat + description:Slot 3 - Silver Wrist + code:7E14FB:44 + cheat + description:Slot 3 - Silver Plate + code:7E14FB:45 + cheat + description:Slot 3 - Zircon Wrist + code:7E14FB:46 + cheat + description:Slot 3 - Zircon Plate + code:7E14FB:47 + cheat + description:Slot 3 - Cloth Helm + code:7E14FB:48 + cheat + description:Slot 3 - Tan Helm + code:7E14FB:49 + cheat + description:Slot 3 - Hair Band + code:7E14FB:4A + cheat + description:Slot 3 - Wood Helm + code:7E14FB:4B + cheat + description:Slot 3 - Glass Cap + code:7E14FB:4C + cheat + description:Slot 3 - Brone Helm + code:7E14FB:4D + cheat + description:Slot 3 - Red Beret + code:7E14FB:4E + cheat + description:Slot 3 - Iron Helm + code:7E14FB:4F + cheat + description:Slot 3 - Plate Cap + code:7E14FB:50 + cheat + description:Slot 3 - Plate Helm + code:7E14FB:51 + cheat + description:Slot 3 - Glass Beret + code:7E14FB:52 + cheat + description:Slot 3 - Silver Helm + code:7E14FB:53 + cheat + description:Slot 3 - Sakret + code:7E14FB:54 + cheat + description:Slot 3 - Zircon Beret + code:7E14FB:55 + cheat + description:Slot 3 - Zircon Helm + code:7E14FB:56 + cheat + description:Slot 3 - Sandal + code:7E14FB:57 + cheat + description:Slot 3 - Cloth Shoes + code:7E14FB:58 + cheat + description:Slot 3 - Tan Shoes + code:7E14FB:59 + cheat + description:Slot 3 - Spike Shoes + code:7E14FB:5A + cheat + description:Slot 3 - Heeled Shoes + code:7E14FB:5B + cheat + description:Slot 3 - Wind Shoes + code:7E14FB:5C + cheat + description:Slot 3 - Wind Heels + code:7E14FB:5D + cheat + description:Slot 3 - Knife Shoes + code:7E14FB:5E + cheat + description:Slot 3 - Needle Heels + code:7E14FB:5F + cheat + description:Slot 3 - Sonic Shoes + code:7E14FB:60 + cheat + description:Slot 3 - Sonic Heels + code:7E14FB:61 + cheat + description:Slot 3 - Sword Shoes + code:7E14FB:62 + cheat + description:Slot 3 - Cat Heels + code:7E14FB:63 + cheat + description:Slot 3 - Mach Shoes + code:7E14FB:64 + cheat + description:Slot 3 - Mach Heels + code:7E14FB:65 + cheat + description:Slot 3 - Power Ring + code:7E14FB:66 + cheat + description:Slot 3 - HiPower Ring + code:7E14FB:67 + cheat + description:Slot 3 - Daze Ring + code:7E14FB:68 + cheat + description:Slot 3 - Hi Daze Ring + code:7E14FB:69 + cheat + description:Slot 3 - Mind Ring + code:7E14FB:6A + cheat + description:Slot 3 - Sonic Ring + code:7E14FB:6B + cheat + description:Slot 3 - Mach Ring + code:7E14FB:6C + cheat + description:Slot 3 - Undead Ring + code:7E14FB:6D + cheat + description:Slot 3 - Ghost Ring + code:7E14FB:6E + cheat + description:Slot 3 - Dragon Ring + code:7E14FB:6F + cheat + description:Slot 3 - Sea Ring + code:7E14FB:70 + cheat + description:Slot 3 - Fly Ring + code:7E14FB:71 + cheat + description:Slot 3 - Water Ring + code:7E14FB:72 + cheat + description:Slot 3 - Fire Ring + code:7E14FB:73 + cheat + description:Slot 3 - Ice Ring + code:7E14FB:74 + cheat + description:Slot 3 - Electro Ring + code:7E14FB:75 + cheat + description:Slot 3 - Flash Ring + code:7E14FB:76 + cheat + description:Slot 3 - Flame Ring + code:7E14FB:77 + cheat + description:Slot 3 - Water Ring + code:7E14FB:78 + cheat + description:Slot 3 - Blast Ring + code:7E14FB:79 + cheat + description:Slot 3 - Frost Ring + code:7E14FB:7A + cheat + description:Slot 3 - Might Armor + code:7E14FB:7B + cheat + description:Slot 3 - Might Shield + code:7E14FB:7C + cheat + description:Slot 3 - Might Helmet + code:7E14FB:7D + cheat + description:Slot 3 - Gloom Ring + code:7E14FB:7E + cheat + description:Slot 3 - Gloom Voice + code:7E14FB:7F + cheat + description:Slot 3 - Dummy (?) + code:7E14FB:80 + cheat + description:Slot 3 - Brone Breast + code:7E14FB:81 + cheat + description:Slot 3 - Carbo Sword + code:7E14FB:82 + cheat + description:Slot 3 - Carbo Plate + code:7E14FB:83 + cheat + description:Slot 3 - Carbo Shield + code:7E14FB:84 + cheat + description:Slot 3 - Carbo Helm + code:7E14FB:85 + cheat + description:Slot 3 - Carbo Cap + code:7E14FB:86 + cheat + description:Slot 3 - Gloom Guard + code:7E14FB:87 + cheat + description:Slot 3 - Diamond Ring + code:7E14FB:88 + cheat + description:Slot 3 - Engage Ring + code:7E14FB:89 + cheat + description:Slot 3 - Monster Ring + code:7E14FB:8A + cheat + description:Slot 3 - Blue Ring + code:7E14FB:8B + cheat + description:Slot 3 - Yellow Ring + code:7E14FB:8C + cheat + description:Slot 3 - Red Ring + code:7E14FB:8D + cheat + description:Slot 3 - Purple Ring + code:7E14FB:8E + cheat + description:Slot 3 - Green Ring + code:7E14FB:8F + cheat + description:Slot 3 - White Ring + code:7E14FB:90 + cheat + description:Slot 3 - Black Ring + code:7E14FB:91 + cheat + description:Slot 3 - Heavy Ring + code:7E14FB:92 + cheat + description:Slot 3 - Wave Ring + code:7E14FB:93 + cheat + description:Slot 3 - Potion + code:7E14FB:94 + cheat + description:Slot 3 - Hi Potion + code:7E14FB:95 + cheat + description:Slot 3 - Ex Potion + code:7E14FB:96 + cheat + description:Slot 3 - Hi Magic + code:7E14FB:97 + cheat + description:Slot 3 - Ex Magic + code:7E14FB:98 + cheat + description:Slot 3 - Antidote + code:7E14FB:99 + cheat + description:Slot 3 - Sweet Water + code:7E14FB:9A + cheat + description:Slot 3 - Foul Water + code:7E14FB:9B + cheat + description:Slot 3 - Awaken + code:7E14FB:9C + cheat + description:Slot 3 - Stone Cure + code:7E14FB:9D + cheat + description:Slot 3 - Mystery Pin + code:7E14FB:9E + cheat + description:Slot 3 - Shriek + code:7E14FB:9F + cheat + description:Slot 3 - Swing Wing + code:7E14FB:A0 + cheat + description:Slot 3 - Magic Guard + code:7E14FB:A1 + cheat + description:Slot 3 - Power Gourd + code:7E14FB:A2 + cheat + description:Slot 3 - Mind Gourd + code:7E14FB:A3 + cheat + description:Slot 3 - Power Potion + code:7E14FB:A4 + cheat + description:Slot 3 - Spell Potion + code:7E14FB:A5 + cheat + description:Slot 3 - Speed Potion + code:7E14FB:A6 + cheat + description:Slot 3 - Mind Potion + code:7E14FB:A7 + cheat + description:Slot 3 - Great Potion + code:7E14FB:A8 + cheat + description:Slot 3 - Float + code:7E14FB:A9 + cheat + description:Slot 3 - Smoke Ball + code:7E14FB:AA + cheat + description:Slot 3 - Arrow + code:7E14FB:AB + cheat + description:Slot 3 - Mid Arrow + code:7E14FB:AC + cheat + description:Slot 3 - Big Arrow + code:7E14FB:AD + cheat + description:Slot 3 - Arrows + code:7E14FB:AE + cheat + description:Slot 3 - Hi Arrows + code:7E14FB:AF + cheat + description:Slot 3 - Ex Arrows + code:7E14FB:B0 + cheat + description:Slot 3 - Dragon Arrow + code:7E14FB:B1 + cheat + description:Slot 3 - Sleep Arrow + code:7E14FB:B2 + cheat + description:Slot 3 - Puzzle Arrow + code:7E14FB:B3 + cheat + description:Slot 3 - Stun Arrow + code:7E14FB:B4 + cheat + description:Slot 3 - Gloom Arrow + code:7E14FB:B5 + cheat + description:Slot 3 - Bomb + code:7E14FB:B6 + cheat + description:Slot 3 - Hi Bomb + code:7E14FB:B7 + cheat + description:Slot 3 - Ex Bomb + code:7E14FB:B8 + cheat + description:Slot 3 - Miracle + code:7E14FB:B9 + cheat + description:Slot 3 - Revive + code:7E14FB:BA + cheat + description:Slot 3 - Pear Cider + code:7E14FB:BB + cheat + description:Slot 3 - Sour Cider + code:7E14FB:BC + cheat + description:Slot 3 - Lime Cider + code:7E14FB:BD + cheat + description:Slot 3 - Plum Cider + code:7E14FB:BE + cheat + description:Slot 3 - Apple Cider + code:7E14FB:BF + cheat + description:Slot 3 - Hair Band + code:7E14FB:C0 + cheat + description:Slot 3 - Brooch + code:7E14FB:C1 + cheat + description:Slot 3 - Earring + code:7E14FB:C2 + cheat + description:Slot 3 - Necklace + code:7E14FB:C3 + cheat + description:Slot 3 - Stuffed Bear + code:7E14FB:C4 + cheat + description:Slot 3 - Stuffed Dog + code:7E14FB:C5 + cheat + description:Slot 3 - Stuffed Pig + code:7E14FB:C6 + cheat + description:Slot 3 - Emerald + code:7E14FB:C7 + cheat + description:Slot 3 - Opal + code:7E14FB:C8 + cheat + description:Slot 3 - Goblet + code:7E14FB:C9 + cheat + description:Slot 3 - Ear Tip + code:7E14FB:CA + cheat + description:Slot 3 - Empty Bottle + code:7E14FB:CB + cheat + description:Slot 3 - Gown + code:7E14FB:CC + cheat + description:Slot 3 - Ribbon + code:7E14FB:CD + cheat + description:Slot 3 - Fry Pan + code:7E14FB:CE + cheat + description:Slot 3 - Small Knife + code:7E14FB:CF + cheat + description:Slot 3 - Pot + code:7E14FB:D0 + cheat + description:Slot 3 - Chop Block + code:7E14FB:D1 + cheat + description:Slot 3 - Apron + code:7E14FB:D2 + cheat + description:Slot 3 - Dragon Egg + code:7E14FB:D3 + cheat + description:Slot 3 - Crown + code:7E14FB:D4 + cheat + description:Slot 3 - Secret Map + code:7E14FB:D5 + cheat + description:Slot 3 - Miracle Gem + code:7E14FB:D6 + cheat + description:Slot 3 - Silver Wick + code:7E14FB:D7 + cheat + description:Slot 3 - Royal Statue + code:7E14FB:D8 + cheat + description:Slot 3 - Silver Tarot + code:7E14FB:D9 + cheat + description:Slot 3 - Golden Pawn + code:7E14FB:DA + cheat + description:Slot 3 - Crown Jewels + code:7E14FB:DB + cheat + description:Slot 3 - Wind Flute + code:7E14FB:DC + cheat + description:Slot 3 - Escape + code:7E14FB:DD + cheat + description:Slot 3 - Magic Jar + code:7E14FB:DE + cheat + description:Slot 3 - Dragon Tooth + code:7E14FB:DF + cheat + description:Slot 3 - Grilled Newt + code:7E14FB:E0 + cheat + description:Slot 3 - Poison Pin + code:7E14FB:E1 + cheat + description:Slot 3 - Might Sword + code:7E14FB:E2 + cheat + description:Slot 3 - Straw Doll + code:7E14FB:E3 + cheat + description:Slot 3 - Long Nail + code:7E14FB:E4 + cheat + description:Slot 3 - Bomb + code:7E14FB:E5 + cheat + description:Slot 3 - Alumina + code:7E14FB:E6 + cheat + description:Slot 3 - Power Oil + code:7E14FB:E7 + cheat + description:Slot 3 - Elven Bow + code:7E14FB:E8 + cheat + description:Slot 3 - Artea's Bow + code:7E14FB:E9 + cheat + description:Slot 3 - Might Bow + code:7E14FB:EA + cheat + description:Slot 3 - Dummy (?) + code:7E14FB:EB + cheat + description:Slot 3 - Dummy (?) + code:7E14FB:EC + cheat + description:Slot 3 - Dummy (?) + code:7E14FB:ED + cheat + description:Slot 3 - Dummy (?) + code:7E14FB:EE + cheat + description:Slot 3 - Free Door + code:7E14FB:EF + cheat + description:Slot 3 - Sheran Key + code:7E14FB:F0 + cheat + description:Slot 3 - Letter + code:7E14FB:F1 + cheat + description:Slot 3 - Dais Key + code:7E14FB:F2 + cheat + description:Slot 3 - Shrine Key + code:7E14FB:F3 + cheat + description:Slot 3 - Pirate Key + code:7E14FB:F4 + cheat + description:Slot 3 - Light Key + code:7E14FB:F5 + cheat + description:Slot 3 - Oil Key + code:7E14FB:F6 + cheat + description:Slot 3 - Green Jade + code:7E14FB:FB + cheat + description:Slot 3 - Red Sapphire + code:7E14FB:F8 + cheat + description:Slot 3 - Blue Jade + code:7E14FB:F9 + cheat + description:Slot 3 - Purple Newt + code:7E14FB:FA + cheat + description:Slot 3 - Glasdar Key + code:7E14FB:FB + cheat + description:Slot 3 - Magic Flavor + code:7E14FB:FC + cheat + description:Slot 3 - Fairy Kiss + code:7E14FB:FD + +cartridge sha256:7c34ecb16c10f551120ed7b86cfbc947042f479b52ee74bb3c40e92fdd192b3a + title:Lufia II - Rise of the Sinistrals (USA) + cheat + description:Infinite 999 MP in and out of battle + code:EEEE-44D9 + cheat + description:Level 99 after one battle + code:6EEB-17A1 + cheat + description:Level 83 after one battle + code:EEEB-17A1 + cheat + description:Gain 35,000 gold after a battle + code:EEED-4F05 + cheat + description:Enemies always miss + code:EEE5-4FD5 + cheat + description:One hit kills + code:EEE7-44D5 + cheat + description:No random battles on world map + code:7E11E3:00 + cheat + description:9999999 GP + code:7E0A8A:7F+7E0A8B:96+7E0A8C:98 + cheat + description:9999999 Coins + code:7E0B55:7F+7E0B56:96+7E0B57:98 + cheat + description:All warps + code:7E098D:FF+7E098E:FF+7E098F:FF+7E0981:FF+7E0990:FF+7E0982:FF+7E097B:FF+7E0983:FF+7E097C:FF+7E097D:FF+7E097E:FF+7E097F:FF+7E0980:FF+7E0986:FF+7E0988:FF+7E0989:FF+7E0991:FF+7E098A:FF+7E0992:FF+7E098B:FF+7E0996:FF+7E098C:FF + cheat + description:P1 - 999 HP + code:7E0BBE:E7+7E0BBF:03 + cheat + description:P1 - 999 MP + code:7E0BC0:E7+7E0BC1:03 + cheat + description:P1 - 999 MAX MP + code:7E0BD4:E7+7E0BD5:03 + cheat + description:P1 - 999 STP + code:7E0BFE:E7+7E0BFF:03 + cheat + description:P1 - 999 DFP + code:7E0C00:E7+7E0C01:03 + cheat + description:P1 - 999 STR + code:7E0C02:E7+7E0C03:03 + cheat + description:P1 - 999 AGL + code:7E0C04:E7+7E0C05:03 + cheat + description:P1 - 999 INT + code:7E0C06:E7+7E0C07:03 + cheat + description:P1 - 999 GUT + code:7E0C08:E7+7E0C09:03 + cheat + description:P1 - 999 MGR + code:7E0C0A:E7+7E0C0B:03 + cheat + description:P1 - Max IP + code:7E0C69:FF + cheat + description:P2 - 999 HP + code:7E0C7C:E7+7E0C7D:03 + cheat + description:P2 - 999 MP + code:7E0C7E:E7+7E0C7F:03 + cheat + description:P2 - 999 MAX MP + code:7E0C92:E7+7E0C93:03 + cheat + description:P2 - 999 STP + code:7E0CBC:E7+7E0CBD:03 + cheat + description:P2 - 999 DFP + code:7E0CBE:E7+7E0CBF:03 + cheat + description:P2 - 999 STR + code:7E0CC0:E7+7E0CC1:03 + cheat + description:P2 - 999 AGL + code:7E0CC2:E7+7E0CC3:03 + cheat + description:P2 - 999 INT + code:7E0CC4:E7+7E0CC5:03 + cheat + description:P2 - 999 GUT + code:7E0CC6:E7+7E0CC7:03 + cheat + description:P2 - 999 MGR + code:7E0CC8:E7+7E0CC9:03 + cheat + description:P2 - Max IP + code:7E0D27:FF + cheat + description:P3 - 999 HP + code:7E0D3A:E7+7E0D3B:03 + cheat + description:P3 - 999 MP + code:7E0D3C:E7+7E0D3D:03 + cheat + description:P3 - 999 MAX MP + code:7E0D50:E7+7E0D51:03 + cheat + description:P3 - 999 STP + code:7E0D7A:E7+7E0D7B:03 + cheat + description:P3 - 999 DFP + code:7E0D7C:E7+7E0D7D:03 + cheat + description:P3 - 999 STR + code:7E0D7E:E7+7E0D7F:03 + cheat + description:P3 - 999 AGL + code:7E0D80:E7+7E0D81:03 + cheat + description:P3 - 999 INT + code:7E0D82:E7+7E0D83:03 + cheat + description:P3 - 999 GUT + code:7E0D84:E7+7E0D85:03 + cheat + description:P3 - 999 MGR + code:7E0D86:E7+7E0D87:03 + cheat + description:P3 - Max IP + code:7E0DE5:FF + cheat + description:P4 - 999 HP + code:7E0DF8:E7+7E0DF9:03 + cheat + description:P4 - 999 MP + code:7E0DFA:E7+7E0DFB:03 + cheat + description:P4 - 999 MAX MP + code:7E0E0E:E7+7E0E0F:03 + cheat + description:P4 - 999 STP + code:7E0E38:E7+7E0E39:03 + cheat + description:P4 - 999 DFP + code:7E0E3A:E7+7E0E3B:03 + cheat + description:P4 - 999 STR + code:7E0E3C:E7+7E0E3D:03 + cheat + description:P4 - 999 AGL + code:7E0E3E:E7+7E0E3F:03 + cheat + description:P4 - 999 INT + code:7E0E40:E7+7E0E41:03 + cheat + description:P4 - 999 GUT + code:7E0E42:E7+7E0E43:03 + cheat + description:P4 - 999 MGR + code:7E0E44:E7+7E0E45:03 + cheat + description:P4 - Max IP + code:7E0EA3:FF + cheat + description:P5 - 999 HP + code:7E0EB6:E7+7E0EB7:03 + cheat + description:P5 - 999 MP + code:7E0EB8:E7+7E0EB9:03 + cheat + description:P5 - 999 MAX MP + code:7E0ECC:E7+7E0ECC:03 + cheat + description:P5 - 999 STP + code:7E0EF6:E7+7E0EF7:03 + cheat + description:P5 - 999 DFP + code:7E0EF8:E7+7E0EF9:03 + cheat + description:P5 - 999 STR + code:7E0EFA:E7+7E0EFB:03 + cheat + description:P5 - 999 AGL + code:7E0EFC:E7+7E0EFD:03 + cheat + description:P5 - 999 INT + code:7E0EFE:E7+7E0EFF:03 + cheat + description:P5 - 999 GUT + code:7E0F00:E7+7E0F01:03 + cheat + description:P5 - 999 MGR + code:7E0F02:E7+7E0F03:03 + cheat + description:P5 - Max IP + code:7E0F61:FF + cheat + description:P6 - 999 HP + code:7E0F74:E7+7E0F75:03 + cheat + description:P6 - 999 MP + code:7E0F76:E7+7E0F77:03 + cheat + description:P6 - 999 MAX MP + code:7E0F8A:E7+7E0F8B:03 + cheat + description:P6 - 999 STP + code:7E0FB4:E7+7E0FB5:03 + cheat + description:P6 - 999 DFP + code:7E0FB6:E7+7E0FB7:03 + cheat + description:P6 - 999 STR + code:7E0FB8:E7+7E0FB9:03 + cheat + description:P6 - 999 AGL + code:7E0FBA:E7+7E0FBB:03 + cheat + description:P6 - 999 INT + code:7E0FBC:E7+7E0FBD:03 + cheat + description:P6 - 999 GUT + code:7E0FBE:E7+7E0FBF:03 + cheat + description:P6 - 999 MGR + code:7E0FC0:E7+7E0FC1:03 + cheat + description:P6 - Max IP + code:7E101F:FF + cheat + description:P7 - 999 HP + code:7E1032:E7+7E1033:03 + cheat + description:P7 - 999 MP + code:7E1034:E7+7E1035:03 + cheat + description:P7 - 999 MAX MP + code:7E1048:E7+7E1049:03 + cheat + description:P7 - 999 STP + code:7E1072:E7+7E1073:03 + cheat + description:P7 - 999 DFP + code:7E1074:E7+7E1075:03 + cheat + description:P7 - 999 STR + code:7E1076:E7+7E1077:03 + cheat + description:P7 - 999 AGL + code:7E1078:E7+7E1079:03 + cheat + description:P7 - 999 INT + code:7E107A:E7+7E107B:03 + cheat + description:P7 - 999 GUT + code:7E107C:E7+7E107D:03 + cheat + description:P7 - 999 MGR + code:7E107E:E7+7E107F:03 + cheat + description:P7 - Max IP + code:7E10DD:FF + +cartridge sha256:7e77e196db47e87a5b297e60f0dfa7ce41df8d2d1fdd9152e06628d0b0e586af + title:Madden NFL '94 (USA) + cheat + description:Always 1st down + code:3CAC-5DDD + cheat + description:1 play to get a 1st down + code:D4A8-54AD + cheat + description:2 plays to get a 1st down + code:D7A8-54AD + cheat + description:3 plays to get a 1st down + code:D0A8-54AD + cheat + description:5 plays to get a 1st down + code:D1A8-54AD + cheat + description:7 plays to get a 1st down + code:D6A8-54AD + cheat + description:Extra points worth 0 points + code:DDAE-ED0F + cheat + description:Extra points worth 3 points + code:D7AE-ED0F + cheat + description:Extra points worth 5 points + code:D9AE-ED0F + cheat + description:Extra points worth 7 points + code:D5AE-ED0F + cheat + description:Field goals worth 0 points + code:DDAE-E76F + cheat + description:Field goals worth 2 points + code:D4AE-E76F + cheat + description:Field goals worth 5 points + code:D9AE-E76F + cheat + description:Field goals worth 7 points + code:D5AE-E76F + cheat + description:Field goals worth 9 points + code:DBAE-E76F + cheat + description:Safeties worth 0 points + code:DDAB-8DAD + cheat + description:Safeties worth 3 points + code:D7AB-8DAD + cheat + description:Safeties worth 5 points + code:D9AB-8DAD + cheat + description:Safeties worth 7 points + code:D5AB-8DAD + cheat + description:Touchdowns worth 0 points + code:DDAA-5D0F + cheat + description:Touchdowns worth 3 points + code:D7AA-5D0F + cheat + description:Touchdowns worth 5 points + code:D9AA-5D0F + cheat + description:Touchdowns worth 9 points + code:DBAA-5D0F + cheat + description:TD, FG, PAT, S worth 1 point - home team + code:CBA2-8F6D+DFA2-8FAD + cheat + description:TD, FG, PAT, S worth 3 points - home team + code:CBA2-8F6D+D7A2-8FAD + cheat + description:TD, FG, PAT, S worth 5 points - home team + code:CBA2-8F6D+D9A2-8FAD + cheat + description:TD, FG, PAT, S worth 7 points - home team + code:CBA2-8F6D+D5A2-8FAD + cheat + description:TD, FG, PAT, S worth 14 points - home team + code:CBA2-8F6D+D3A2-8FAD + cheat + description:TD, FG, PAT, S worth 21 points - home team + code:CBA2-8F6D+F9A2-8FAD + cheat + description:TD, FG, PAT, S worth 35 points - home team + code:CBA2-8F6D+47A2-8FAD + cheat + description:TD, FG, PAT, S worth 3 points - visitor + code:CBAD-ED0D+DFAD-ED6D + cheat + description:TD, FG, PAT, S worth 5 points - visitor + code:CBAD-ED0D+D9AD-ED6D + cheat + description:TD, FG, PAT, S worth 7 points - visitor + code:CBAD-ED0D+D5AD-ED6D + cheat + description:TD, FG, PAT, S worth 14 points - visitor + code:CBAD-ED0D+D3AD-ED6D + cheat + description:TD, FG, PAT, S worth 21 points - visitor + code:CBAD-ED0D+F9AD-ED6D + cheat + description:TD, FG, PAT, S worth 35 points - visitor + code:CBAD-ED0D+47AD-ED6D + cheat + description:Home team starts with a 3-point lead + code:D73F-7D0F+DE3F-7F6F + cheat + description:Home team starts with a 7-point lead + code:D53F-7D0F+DE3F-7F6F + cheat + description:Home team starts with a 10-point lead + code:DC3F-7D0F+DE3F-7F6F + cheat + description:Home team starts with a 14-point lead + code:D33F-7D0F+DE3F-7F6F + cheat + description:Home team starts with a 35-point lead + code:473F-7D0F+DE3F-7F6F + cheat + description:Visitors start with a 5-point lead + code:D93F-7D0F+DE3F-7D6F + cheat + description:Visitors start with a 7-point lead + code:D53F-7D0F+DE3F-7D6F + cheat + description:Visitors start with a 10-point lead + code:DC3F-7D0F+DE3F-7D6F + cheat + description:Visitors start with a 14-point lead + code:D33F-7D0F+DE3F-7D6F + cheat + description:Visitors start with a 35-point lead + code:473F-7D0F+DE3F-7D6F + +cartridge sha256:0ad77ae7af231313e1369a52d1622b88e3751aa5ec774628df7071f9e4244abc + title:Madden NFL 95 (USA) + cheat + description:Always 1st down + code:C267-E46D + cheat + description:Infinite timeouts - both players (slightly glitchy) + code:8250-5700 + cheat + description:Field goals worth 0 points + code:DD6F-8404 + cheat + description:Field goals worth 1 points + code:DF6F-8404 + cheat + description:Field goals worth 5 points + code:D06F-8404 + cheat + description:Field goals worth 9 points + code:DB6F-8404 + cheat + description:Safetys worth 0 points + code:DD6F-77AF + cheat + description:Safetys worth 1 points + code:DF6F-77AF + cheat + description:Safetys worth 5 points + code:D06F-77AF + cheat + description:Safetys worth 7 points + code:D56F-77AF + cheat + description:Touchdowns worth 0 points + code:DD62-E4DF + cheat + description:Touchdowns worth 1 points + code:DF62-E4DF + cheat + description:Touchdowns worth 5 points + code:D062-E4DF + cheat + description:Touchdowns worth 9 points + code:DB62-E4DF + cheat + description:Start with 15 seconds on the play clock + code:DE55-84DF + cheat + description:Start with 1 timeout - P1 + code:DFD0-7DAD + cheat + description:Start with 1 timeout - P2 + code:DFD0-7FDD + +cartridge sha256:3059d86cdc383985c564a7a891fe18e08f5222ead7ede9fa309159d60cde13a1 + title:Madden NFL 96 (USA) + cheat + description:Infinite time (2P mode only) + code:C2D2-8F0D + cheat + description:Infinite downs + code:C26A-8767 + cheat + description:Infinite timeouts + code:8297-7F09 + cheat + description:Safeties are worth 0 points + code:DD62-EFA7 + cheat + description:Safeties are worth 1 point + code:DF62-EFA7 + cheat + description:Safeties are worth 3 points + code:D462-EFA7 + cheat + description:Safeties are worth 5 points + code:D962-EFA7 + cheat + description:Safeties are worth 7 points + code:D562-EFA7 + cheat + description:Safeties are worth 9 points + code:DB62-EFA7 + cheat + description:Field Goals are worth 0 points + code:DDBB-8DAF + cheat + description:Field Goals are worth 1 point + code:DFBB-8DAF + cheat + description:Field Goals are worth 2 points + code:D4BB-8DAF + cheat + description:Field Goals are worth 5 points + code:D9BB-8DAF + cheat + description:Field Goals are worth 7 points + code:D5BB-8DAF + cheat + description:Field Goals are worth 9 points + code:DBBB-8DAF + cheat + description:Start with 5 downs each possession + code:DD65-E7A7 + cheat + description:Start with 3 downs each possession + code:D765-E7A7 + cheat + description:Start with 2 downs each possession + code:D465-E7A7 + cheat + description:Start with 1 down each possession + code:DF65-E7A7 + +cartridge sha256:c01fb8989d391d3e343003934937f02bd8ef9aacdad68c32c3d3f56feb72f5b0 + title:Magic Boy (USA) + cheat + description:Infinite lives + code:7E9BB6:03 + +cartridge sha256:1d3cceaa05e054b002caeb09fd5fb9e718ec446764f4169d97bc185da76fdf4d + title:Magic Sword (USA) + cheat + description:No health loss on collision with enemies + code:C2BC-D7A5+C280-D7DD + cheat + description:No health loss when magic is used + code:C2B4-6FD9 + cheat + description:No magic counter countdown + code:C2CC-0F67 + cheat + description:Hit anywhere + code:3C67-046A+C267-0FAA+D667-04DA+ED67-04AA+F167-040A + cheat + description:One hit kills + code:6D63-D40A + cheat + description:Slower magic counter countdown + code:5ECC-0D67 + cheat + description:Faster magic counter countdown + code:EECC-0D67 + cheat + description:Invincibility + code:7E831C:09 + cheat + description:Infinite continues + code:7E042D:09 + cheat + description:Infinite health + code:7E0432:09 + cheat + description:Infinite support health + code:7E0423:04 + cheat + description:Infinite magic + code:7E040C:09+7E040D:09 + cheat + description:Have powered-up attack + code:7E068A:06 + cheat + description:Infinite Silver Keys + code:7E040F:09 + cheat + description:Infinite Gold Keys + code:7E0410:09 + cheat + description:Infinite Platinum Keys + code:7E0411:09 + cheat + description:Have optimum sword + code:7E040A:06 + cheat + description:Have optimum shield + code:7E040B:04 + cheat + description:Never lose shield + code:7E0435:02 + cheat + description:Barrier Invincibility + code:7E06D6:FF + cheat + description:Set score to 90,000,000 + code:7E0448:09 + cheat + description:Support modifier - Amazon + code:7E0424:03 + cheat + description:Support modifier - Big Man + code:7E0424:07 + cheat + description:Support modifier - Wizard + code:7E0424:09 + cheat + description:Support modifier - Knight + code:7E0424:0C + cheat + description:Support modifier - Lizardman + code:7E0424:0F + cheat + description:Support modifier - Ninja + code:7E0424:12 + cheat + description:Support modifier - Thief + code:7E0424:15 + cheat + description:Support modifier - Cleric + code:7E0424:18 + cheat + description:Max power for Amazon's Crossbow + code:7E0413:07 + cheat + description:Max power for Big Man's Axe + code:7E0414:07 + cheat + description:Max power for Wizard's Magic Missile + code:7E0415:07 + cheat + description:Max power for Knight's Spear + code:7E0416:07 + cheat + description:Max power for Lizardman's Sword + code:7E0417:07 + cheat + description:Max power for Ninja's Throwing Star + code:7E0418:07 + cheat + description:Max power for Thief's Bomb + code:7E0419:07 + cheat + description:Max power for Cleric's Magic Bullet + code:7E041A:07 + +cartridge sha256:ed617ad12c865fc9c9c5c75de840d3afeded57d13ca3a3062bf8e30095629414 + title:Magical Pop'n (Japan) + cheat + description:Infinite health + code:7E051A:06 + cheat + description:Infinite lives + code:7E0516:02 + cheat + description:Infinite stars + code:7E0508:09 + +cartridge sha256:f301bb8ea867e530ecb64e8eff504ed5b9697cf076c70e2036ecf2ffbe6c487a + title:Magical Quest Starring Mickey Mouse, The (USA) + cheat + description:Protection from most hits (lose no hearts) (disable if you get stuck) + code:C2E7-D462 + cheat + description:Infinite magic - wizard's costume only + code:C23E-6405 + cheat + description:Infinite lives + code:C22B-ADA5 + cheat + description:Small heart fill health completely + code:622F-DDD6+C22F-DF06 + cheat + description:Each gold coin worth 10 (if too many are collected you may go back to 0) + code:DFE7-0708 + cheat + description:Longer invincibility after getting hit + code:C23D-6FA0 + cheat + description:No invincibility after getting hit + code:CB3D-6D60 + cheat + description:Super-jump + code:1B2D-6765+4A2D-67A5 + cheat + description:Mega-jump + code:1B2D-6765+4D2D-67A5 + cheat + description:Ultra-jump + code:1B2D-6765+F02D-67A5 + cheat + description:Items in general store are free if you can afford them + code:6DE6-04A8+48E6-07D8 + cheat + description:Start with 1 heart instead of 3 + code:DFAE-D4D7 + cheat + description:Start with 5 hearts + code:D9AE-D4D7 + cheat + description:Start with 7 hearts + code:D5AE-D4D7 + cheat + description:Start with 10 hearts + code:DCAE-D4D7 + cheat + description:Start with 1 life instead of 3 + code:DD69-07A0 + cheat + description:Start with 7 lives + code:D169-07A0 + cheat + description:Start with 10 lives + code:DB69-07A0 + cheat + description:Invincibility after first hit + code:7E033F:03 + cheat + description:Infinite health + code:7E02B1:0A + cheat + description:Infinite magic + code:7E02B7:20 + cheat + description:Infinite water for Fireman costume + code:7E02B9:17 + cheat + description:Infinite lives (alt) + code:01DF93:AD + cheat + description:Have all costumes + code:7E02C1:01+7E02C2:01+7E02C3:01 + cheat + description:Mega-jump + code:7E04B0:1A + cheat + description:Ultra-jump + code:7E04B0:06 + +cartridge sha256:78d0f6dd9ce0813e0532c7b25c7fa0b6b945d12a4ace21aa940e98babf4dacb1 + title:Majuu Ou (Japan) + cheat + description:Infinite health + code:7E009F:50 + cheat + description:Infinite lives + code:7E00A3:01 + +cartridge sha256:8267e2f092c86d5a29c9a826db82c7473638e28e2507cdaf5c86981f07cd0bef + title:Mario Is Missing! (USA) + cheat + description:Talk to someone once to learn all they know (all four checks appear on computer for that person) + code:CB8D-17DF+EE8D-170F+3C8D-176F + cheat + description:Use computer to access any facts except pamphlets (no checks appear on computer) + code:6D8D-C4AF+DD80-C70F+DD85-C4DF + cheat + description:Use computer to view pamphlets on any artifact (no checks appear on computer) + code:6D82-17AF + cheat + description:Always get Yoshi after using Globulator + code:DFED-4D04 + cheat + description:Pick up one artifact and get all three + code:CB8E-47AF+EE8D-1DDF+3C8D-1D0F + cheat + description:Have all three arifacts + code:7E050A:07 + cheat + description:Always have Yoshi (Globulator doesn't automatically pick your location) + code:7E06DB:01 + cheat + description:No waiting on wrong answer + code:7E0565:00 + +cartridge sha256:e842cac1a4301be196f1e137fbd1a16866d5c913f24dbca313f4dd8bd7472f45 + title:Mario Paint (Japan, USA) + cheat + description:Invincibility in bug swatting game + code:CBCF-0769+62C4-0DA9+EECF-07A9 + cheat + description:Infinite lives in bug swatting game + code:A2C3-6409 + cheat + description:Have all icons in bug swatting game + code:CBC4-A400 + cheat + description:Star easier to get under "P" on title screen + code:DD69-1F52+DD69-1452+DF69-1482 + cheat + description:Invincibility in bug swatting game (alt) + code:7F0040:FF + cheat + description:Infinite lives in bug swatting game (alt) + code:7F0018:63 + cheat + description:Have all icons in bug swatting game (alt) + code:7F0012:0F + cheat + description:Only need to swat once to move around and kill flies + code:7F001E:02 + cheat + description:Enable all rotate/flip options + code:7E099F:01 + cheat + description:One hit to kill boss + code:7F00C9:14 + cheat + description:Start on level 2 + code:7F0014:01 + cheat + description:Start on level 3 + code:7F0014:02 + +cartridge sha256:4b69d4958e099c3b3f6ae45e153ced9b24755d8c161dfee06c9f67886a7c0f09 + title:Mario's Time Machine (USA) + cheat + description:Bonus timer doesn't count down in the whole game + code:DD6A-1405 + cheat + description:Don't lose mushrooms in collisions + code:CB64-3FA9+DD64-34D7+DD64-3409 + cheat + description:1 wrong answer to questions allowed + code:DF24-1704 + cheat + description:255 wrong answers allowed (ignore sad face icon) + code:EE24-1704 + +cartridge sha256:49dd77b310b476c875633335243553be59ecfb0bffae62e46f2e53ff05c20fcd + title:Marvel Super Heroes - War of the Gems (USA) + cheat + description:Infinite health + code:B9D9-74D4 + cheat + description:Infinite Air + code:B9D9-74D4 + cheat + description:Infinite Air (alt) + code:E15A-5F66 + cheat + description:Infinite equipment, all Gems selectable on pick-up + code:FA85-7464+6D85-7704+FE85-7764 + cheat + description:One hit kills + code:CB1F-EF0D + cheat + description:Always have a Gem + code:B354-E4D8 + cheat + description:Always have 9 Gem power items + code:E916-740D + cheat + description:Always have 9 Revive items + code:E15A-5F66 + cheat + description:Invincibility - Boston Aquarium + code:7E042D:03+7E042F:00 + cheat + description:Invincibility - Alaska + code:7E02CD:03+7E02CF:00 + cheat + description:Invincibility - Dr. Doom's Castle + code:7E02BD:03+7E02BF:00 + cheat + description:Invincibility - Amazon + code:7E02FD:03+7E02FF:00 + cheat + description:Invincibility - Magus' Spaceship and Asteroid Belt + code:7E026D:03+7E026F:00 + cheat + description:Invincibility - Egypt + code:7E02DD:03+7E02DF:00 + cheat + description:Invincibility - Arizona Mining Facility + code:7E031D:03+7E031F:00 + cheat + description:Invincibility - Mt. Vezuvius + code:7E039D:03+7E039F:00 + cheat + description:Invincibility - Nebula's Level + code:7E033D:03+7E033F:00 + cheat + description:Invincibility - Thanos' Level + code:7E034D:03+7E034F:00 + cheat + description:Infinite health - Dr. Doom's Castle + code:7E026B:64 + cheat + description:Infinite health - Alaska + code:7E027B:64 + cheat + description:Infinite health - Mt. Vesuvius + code:7E034B:64 + cheat + description:Infinite health - Egypt + code:7E028B:64 + cheat + description:Infinite health - Arizona Mining Facility + code:7E02CB:64 + cheat + description:Always have 9 Big energy Tanks + code:7FFF1A:09 + cheat + description:Always have 9 Small energy Tanks + code:7FFF1B:09 + +cartridge sha256:2731f0bd1c87e75121f41d1ed5cc9fbf177f414b8bf831c76fd9c4b58c86ed08 + title:Mary Shelley's Frankenstein (USA) + cheat + description:Infinite health + code:C2B9-1DA4+8533-3F0D + cheat + description:Energy balls don't deplete health + code:DDE5-3FB0+DDE5-3F20 + cheat + description:Cool effects + code:??86-146D + cheat + description:Invincibility (blinking) + code:7E200D:09 + cheat + description:Infinite health (alt) + code:7E2043:1D + +cartridge sha256:44cc113ce1e7616cc737adea9e8f140436c9f1c3fba57e8e9db48025d4ace632 + title:Mask, The (USA) + cheat + description:Invincibility after one hit + code:82C0-476F + cheat + description:Infinite mask power + code:C282-1F0D + cheat + description:Infinite lives + code:C961-146F + cheat + description:Mallet doesn't use any power + code:8EBF-3DD4 + cheat + description:Green hearts worth 10 + code:FDC6-3707 + cheat + description:Green hearts worth 30 + code:7DC6-3707 + cheat + description:Green hearts worth 100 + code:CDC6-3707 + cheat + description:Green hearts worth 0 + code:C2CC-3F07 + cheat + description:Flash longer + code:EE88-140D + cheat + description:Don't flash at all + code:DD88-140D + cheat + description:M's worth 0 + code:C9C4-3467 + cheat + description:M's worth 10 + code:FDCF-37A7 + cheat + description:M's worth 30 + code:7DCF-37A7 + cheat + description:M's worth 100 + code:CDCF-37A7 + cheat + description:Start with 100 mask energy + code:DF6E-44AD + cheat + description:Start with 300 mask energy + code:D76E-44AD + cheat + description:Start with 900 mask energy + code:DB6E-44AD + cheat + description:Start with 1 life + code:CB63-446D+DD63-44AD+DD63-47DD + cheat + description:Start with 5 lives + code:CB63-446D+D963-44AD+DD63-47DD + cheat + description:Start with 9 lives + code:CB63-446D+DB63-44AD+DD63-47DD + cheat + description:Infinite life + code:7E18AF:20+7E18B0:03 + cheat + description:Infinite mask power (alt) + code:7E008F:84+7E0090:03 + +cartridge sha256:2a08704748f5ef6488348c4099729feca600412d331bda3756e51efd8b94e113 + title:MechWarrior (USA) + cheat + description:Protection from most hazards + code:628C-4F20 + cheat + description:Infinite short-range missiles + code:EE2F-C7A4 + cheat + description:Infinite short-range homing missiles + code:EE24-CD04 + cheat + description:Infinite medium-range missiles + code:EE24-CDA4 + cheat + description:Infinite medium-range homing missiles + code:EE24-CF04 + cheat + description:Infinite long-range missiles + code:EE24-CFA4 + cheat + description:Infinite long-range homing missiles + code:EE24-C404 + cheat + description:Infinite machine gun ammo + code:EE24-C4A4 + cheat + description:Never run out of any ammo + code:3CCD-4404 + cheat + description:Getting any money sets money to 32 million C-bills + code:DD38-146D + cheat + description:100 ammo for short-range missiles + code:102F-C7A4 + cheat + description:100 ammo for short-range homing missiles + code:1024-CD04 + cheat + description:80 ammo for medium-range missiles + code:9D24-CDA4 + cheat + description:80 ammo for medium-range homing missiles + code:9D24-CF04 + cheat + description:40 ammo for long-range missiles + code:4624-CFA4 + cheat + description:40 ammo for long-range homing missiles + code:4624-C404 + cheat + description:200 short-range missiles + code:A62F-C7A4 + cheat + description:200 short-range homing missiles + code:A624-CD04 + cheat + description:100 medium-range missiles + code:1024-CDA4 + cheat + description:100 medium-range homing missiles + code:1024-CF04 + cheat + description:100 long-range missiles + code:1024-CFA4 + cheat + description:100 long-range homing missiles + code:1024-C404 + cheat + description:Mech isn't slowed down as much by most obstacles + code:CBED-34F7+3CED-34B7 + cheat + description:Start with 100,000 C-bills + code:103E-C4AD + cheat + description:Start with 250,000 C-bills + code:EC3E-C4AD + cheat + description:Start with 562,000 C-bills + code:D43E-C7DD + cheat + description:Start with 1,074,000 C-bills + code:D03E-C7DD + cheat + description:Start with 5,170,000 C-bills + code:F03E-C7DD + cheat + description:Start with 10,290,000 C-bills + code:463E-C7DD + +cartridge sha256:7bffa1dc31604fa3d61e06ce2c59168098cc8dd7e59998e1d5f30c49bdf8d617 + title:MechWarrior 3050 (USA) + cheat + description:Almost infinite ammo + code:C295-5FAD + cheat + description:Almost invincible (disable to kill some enemies) + code:1D9E-ED6D + cheat + description:Coolant does nothing + code:CB6B-5464+CB6B-5704 + cheat + description:Guass Rifle starts at 10 + code:DC09-7998 + cheat + description:Guass Rifle starts at 50 + code:7409-7998 + cheat + description:Guass Rifle starts at 100 + code:1009-7998 + cheat + description:Arrow VI Missiles start at 20 + code:F009-7028 + cheat + description:Arrow VI Missiles start at 50 + code:7409-7028 + cheat + description:Arrow VI Missiles start at 100 + code:1009-7028 + cheat + description:Particle Projection Cannon start at 10 + code:DC00-7528 + cheat + description:Particle Projection Cannon start at 50 + code:7400-7528 + cheat + description:Particle Projection Cannon start at 100 + code:1000-7528 + cheat + description:Machine Gun starts at 100 + code:DD00-79B8+1000-7998 + cheat + description:Machine Gun starts at 1,000 + code:D700-79B8+3600-7998 + cheat + description:Machine Gun starts at 10,000 + code:4100-79B8+FD00-7998 + cheat + description:Auto Cannon starts at 50 + code:7400-7928 + cheat + description:Auto Cannon starts at 100 + code:1000-7928 + cheat + description:Auto Cannon starts at 250 + code:EC00-7928 + cheat + description:Large Laser starts at 50 + code:7400-7128+DD00-75F8 + cheat + description:Large Laser starts at 1,000 + code:3600-7128+D700-75F8 + cheat + description:Large Laser starts at 10,000 + code:FD00-7128+4100-75F8 + cheat + description:"Inferno" Short-Range Missiles start at 10 + code:DC00-7198 + cheat + description:"Inferno" Short-Range Missiles start at 50 + code:7400-7198 + cheat + description:"Inferno" Short-Range Missiles start at 250 + code:EC00-7198 + cheat + description:"Maelstrom" Long-Range Missiles start at 20 + code:F009-7098 + cheat + description:"Maelstrom" Long-Range Missiles start at 100 + code:1009-7098 + cheat + description:"Maelstrom" Long-Range Missiles start at 250 + code:EC09-7098 + cheat + description:"Thunder" Time-Delay Mines start at 10 + code:DC00-7598 + cheat + description:"Thunder" Time-Delay Mines start at 100 + code:1000-7598 + cheat + description:"Thunder" Time-Delay Mines start at 250 + code:EC00-7598 + +cartridge sha256:ee1a030f30f3ab06361921447b3fcf84c987dd13d76e62964e44720e0ec82c56 + title:Mega lo Mania (Europe) (En,Fr,De) + cheat + description:Infinite number of people to use + code:7EE8D9:64 + +cartridge sha256:a255fec32453739903a1954149f19bc9658f4a415600b44badf1d4e5e13a16f9 + title:Mega Man 7 (USA) + cheat + description:Invincibility after first hit (blinking) + code:6D79-84A0 + cheat + description:Infinite health + code:C2DB-5F62 + cheat + description:Infinite health (alt) + code:D9DB-5DA2 + cheat + description:Infinite E-Tanks + code:C209-7DA4 + cheat + description:Infinite W-Tanks + code:C20B-7DD4 + cheat + description:Infinite S-Tanks + code:C20E-7D04 + cheat + description:Infinite Beat Whistles + code:C277-8F00 + cheat + description:Infinite weapon energy + code:FEC2-E405 + cheat + description:One hit kills + code:40DE-7FD2 + cheat + description:Hit anywhere + code:6DD8-7DD2 + cheat + description:Multi-jump + code:DC51-ED65+BD51-EDA5+D751-EFD5+4D51-EF05+8551-EF65+7451-EFA5+4D51-E4D5+BC51-E405+FF51-E465+1D51-E4A5+1DFC-E400+5EFC-E460+C951-EDD5+0951-ED05 + cheat + description:Infinite E-Tanks (alt) + code:7E0BA0:FF + cheat + description:Infinite W-Tanks (alt) + code:7E0BA1:FF + cheat + description:Infinite S-Tanks (alt) + code:7E0BA2:FF + cheat + description:Infinite Beat Whistles (alt) + code:7E0BA3:84 + cheat + description:Infinite Bolts + code:7E0BA6:E7+7E0BA7:03 + cheat + description:Infinite slide + code:7E0C61:FF + cheat + description:Moon-jump + code:7E0C1A:F4 + cheat + description:Have exit + code:7E0BA4:FF + cheat + description:Have S.Adapt + code:7E0B9F:FF + cheat + description:Have Super Fist upgrade for S.Adapt + code:7E0BA4:4F + cheat + description:Have Proto Shield + code:7E0B95:FF + cheat + description:Infinite Feeze Cracker + code:7E0B85:FF + cheat + description:Infinite Junk Shield + code:7E0B89:FF + cheat + description:Infinite Scorch Wheel + code:7E0B8B:FF + cheat + description:Infinite Slash Claw + code:7E0B8D:FF + cheat + description:Infinite Thunder Bolt + code:7E0B87:FF + cheat + description:Infinite Noise Crush + code:7E0B8F:FF + cheat + description:Infinite Danger Wrap + code:7E0B91:FF + cheat + description:Infinite Wild Coil + code:7E0B93:FF + cheat + description:Infinite Rush Coil + code:7E0B9B:FF + cheat + description:Infinite Rush Search + code:7E0B97:FF + cheat + description:Infinite Rush Jet + code:7E0B99:FF + +cartridge sha256:b8f70a6e7fb93819f79693578887e2c11e196bdf1ac6ddc7cb924b1ad0be2d32 + title:Mega Man X (USA) (Rev 1) + cheat + description:Infinite weapons once obtained + code:DDB3-4FA9 + cheat + description:Immune to drain attack + code:C2AD-4401 + cheat + description:One hit kills (most enemies) + code:6DB5-CD97 + cheat + description:Hit anywhere + code:40B1-34F4 + cheat + description:Multi-jump + code:4065-17A9+EA66-1409+B966-1469 + cheat + description:Bogus jump (may go back to normal jumps) + code:D08A-1FBC + cheat + description:Super-jump (may go back to normal jumps) + code:D58A-1FBC + cheat + description:Mega-jump (may go back to normal jumps) + code:DB8A-1FBC + cheat + description:Start with less health + code:D6BE-47AF + cheat + description:Start with more health + code:4DBE-47AF + cheat + description:Start with 10 lives + code:DBBE-446F + cheat + description:Start with 7 lives + code:D1BE-446F + cheat + description:Start with 5 lives + code:D0BE-446F + cheat + description:Start with 1 life + code:DDBE-446F + cheat + description:Max health containers + code:7E1F9A:20 + cheat + description:Infinite lives + code:7E1F80:09 + cheat + description:Have all equipment + code:7E1F99:FF + cheat + description:Enable Hadoken + code:7E1F7E:85 + cheat + description:Have sub-tank 1 full + code:7E1F83:FF + cheat + description:Have sub-tank 2 full + code:7E1F84:FF + cheat + description:Have sub-tank 3 full + code:7E1F85:FF + cheat + description:Have sub-tank 4 full + code:7E1F86:FF + +cartridge sha256:3e1209f473bff8cd4bcbf71d071e7f8df17a2d564e9a5c4c427ee8198cebb615 + title:Mega Man X (USA) + cheat + description:Infinite health + code:C2B9-1FF7 + cheat + description:Infinite lives + code:C2B9-3404 + cheat + description:Infinite weapons once obtained + code:C9B3-4769 + cheat + description:One hit kills (most enemies) + code:6DB5-CD97 + cheat + description:Hit anywhere + code:40B1-34F4 + cheat + description:Weapon charges to 1st power level faster + code:DDB1-4F61 + cheat + description:Disable weapon charging + code:DDB0-4FA1 + cheat + description:Multi-jump + code:4065-1F09+E465-17A9+B966-1DD9 + cheat + description:Bogus jump (may go back to normal jumps) + code:D08A-1FBC + cheat + description:Super-jump (may go back to normal jumps) + code:D58A-1FBC + cheat + description:Mega-jump (may go back to normal jumps) + code:DB8A-1FBC + cheat + description:Start with all weapons and all enemies defeated (except Sigma) + code:23BD-3F07 + cheat + description:Start with less health + code:D6BE-47AF + cheat + description:Start with more health + code:4DBE-47AF + cheat + description:Start with 10 lives + code:DBBE-446F + cheat + description:Start with 7 lives + code:D1BE-446F + cheat + description:Start with 5 lives + code:D0BE-446F + cheat + description:Start with 1 life + code:DDBE-446F + cheat + description:Max health containers + code:7E1F9A:20 + cheat + description:Infinite lives (alt) + code:7E1F80:09 + cheat + description:Have all equipment + code:7E1F99:FF + cheat + description:Have sub-tank 1 full + code:7E1F83:FF + cheat + description:Have sub-tank 2 full + code:7E1F84:FF + cheat + description:Have sub-tank 3 full + code:7E1F85:FF + cheat + description:Have sub-tank 4 full + code:7E1F86:FF + +cartridge sha256:f3246755f608a1e1dc9c848b61da3b824c7853b29b3be40df6fc7f2793a887ed + title:Mega Man X2 (USA) + cheat + description:Infinite health + code:C223-0414 + cheat + description:Infinite health (alt) + code:BA23-0FC4 + cheat + description:One hit kills + code:6D2D-AF14 + cheat + description:Hit anywhere + code:4028-A73F+C222-6734+D4E7-DDFB + cheat + description:Multi-jump + code:40BE-DD44+26BE-D4C4+8BBE-D434 + cheat + description:Invincibility + code:8944008 + cheat + description:Infinite health (alt 2) + code:7E09FF:20 + cheat + description:Max health containers + code:7E1FD1:20 + cheat + description:Infinite lives + code:7E1FB3:09 + cheat + description:Have Shouryuken (F, D, DF + Fire) (must have max health and health containers) + code:7E1FB1:80 + cheat + description:Infinite L.Tracer + code:7E1FCD:5C + cheat + description:Infinite Bubble.S + code:7E1FBD:5C + cheat + description:Infinite Crystal.H + code:7E1FBB:5C + cheat + description:Infinite Magnet.M + code:7E1FC7:5C + cheat + description:Infinite S.Burner + code:7E1FC9:5C + cheat + description:Infinite S.Chain + code:7E1FC5:5C + cheat + description:Infinite S.Slicer + code:7E1FC3:5C + cheat + description:Infinite S.Wheel + code:7E1FC1:5C + cheat + description:Infinite Silk.S + code:7E1FBF:5C + cheat + description:Infinite G.Crush + code:7E1FCB:5C + cheat + description:Infinite Dash + code:7E0A2A:16 + cheat + description:Have all equipment + code:7E1FD0:FF + cheat + description:Have sub-tank 1 full + code:7E1FB6:FF + cheat + description:Have sub-tank 2 full + code:7E1FB7:FF + cheat + description:Have sub-tank 3 full + code:7E1FB8:FF + cheat + description:Have sub-tank 4 full + code:7E1FB9:FF + cheat + description:Have Zero's Head, Body and Legs + code:7E1FD6:80+7E1FD7:80+7E1FD8:80 + +cartridge sha256:65b03268afac296330e8ff8d60dd0825879e13ed658b37713c034a3bd074f1d7 + title:Mega Man X3 (USA) + cheat + description:Infinite health + code:C2AD-6FF7 + cheat + description:Infinite special weapons on pick-up + code:82CB-0D2F+82CA-0F2F + cheat + description:Hit anywhere + code:40AC-A7B4+6DA0-ADF7+6DAF-AD97 + cheat + description:Multi-jump + code:4064-042F+D367-0F9F+C567-0FBF + cheat + description:Super-jump + code:D586-6F26 + cheat + description:Mega-jump + code:DB86-6F26 + cheat + description:Ultra mega-jump + code:D886-6F26 + cheat + description:Normal weapon is much more powerful + code:6DA0-ADF7 + cheat + description:Skip bosses at start of game and proceed to stage select + code:B933-DF6C + cheat + description:Start with max health bar + code:F02A-ADF4 + cheat + description:Invincibility + code:7E0A08:08 + cheat + description:Infinite lives + code:7E1FB4:09 + cheat + description:Infinite Boosts + code:7E0A9A:01 + cheat + description:Get all equipment when you enter the start menu + code:00CD80:A9+00CD81:FF+00CD82:8D+00CD83:D7 + cheat + description:Always have Super Shot + code:7E0A67:02 + cheat + description:Infinite Air Dash + code:7E0A34:78 + cheat + description:Have Zero-Saber + code:7E1FB2:FC + cheat + description:Have all upgrades + code:7E1FD1:4F + cheat + description:Invincible Ride Armor + code:7E0CF8:01 + +cartridge sha256:cf4d603dc0a3759da571224c671a9bfd29f9e52ca8dbb61bcc8ac8be5481e9b2 + title:Mega Man Soccer (USA) + cheat + description:Choose any character to play as Dr. Willy + code:CBCA-3F60+F0CA-3FA0+DDCA-34D0 + cheat + description:View ending (select Capcom Championship) + code:81829B:EE+81829C:E0 + +cartridge sha256:d4f2cb6b209db29f7aec62e5a23846681c14665fb007e94d7bcfc7b5611e938b + title:Metal Combat - Falcon's Revenge (USA) + cheat + description:Infinite health + code:7E1968:7F + cheat + description:No time + code:7E03C5:00+7E03C7:00 + cheat + description:Infinite Bombs + code:7E03FE:08 + cheat + description:Infinite Energy Bolt charge + code:7E1B13:96 + cheat + description:Infinite Treble Energy Bolts + code:7E1B17:03 + +cartridge sha256:0a9609a505dd1555006b16f53d961b3ce50c518aa1597a77dcd46e55ecc716ff + title:Metal Marines (USA) + cheat + description:Building an ICBM only takes up one space + code:6DA1-67AD + cheat + description:Can view entire enemy map + code:6DCE-DD03 + cheat + description:Enemy has no attack phase + code:1D25-64A8 + cheat + description:Instant maximum energy + code:DD25-04AD + cheat + description:Instant maximum war funds + code:DD28-0D0D + cheat + description:Enemy always has 0 energy + code:BA21-07AD + cheat + description:Enemy always has 0 war funds + code:BA2C-0F0D + +cartridge sha256:057484558ebd18165f98e556b994080535e31cefdd98b5edb190516f7040fc9d + title:Metal Morph (USA) + cheat + description:Infinite ammo for all weapons (disable to change weapons) + code:C926-C7A1 + cheat + description:Infinite continues + code:C9A9-4F65 + cheat + description:Infinite time on continue screen + code:C2AD-4D65 + cheat + description:Start with 255 continues + code:EE6C-1FDD + cheat + description:Invincibility + code:7E0387:03 + +cartridge sha256:0d7f875877fe856066cfb39b4ecdbbe7d48393a75770720876c94419f809bb1c + title:Metal Warriors (USA) + cheat + description:Infinite health (Mech) + code:C38F-4DD0 + cheat + description:Infinite health (Human) + code:C9A9-3D60 + cheat + description:Infinite Gun ammo on pick-up + code:306C-1D65 + cheat + description:Press L to go Hyper (Mech) + code:C168-1F05 + +cartridge sha256:1b425ea5a883b7464637b74c2937fde699ffff52b53ad6940a66285e0663194a + title:Michael Jordan - Chaos in the Windy City (USA) + cheat + description:Infinite lives + code:7E1427:05 + cheat + description:Infinite Flame Balls + code:7E594E:05 + cheat + description:Infinite Grenade(?) Balls + code:7E5948:05 + cheat + description:Infinite Homing Balls + code:7E5950:05 + cheat + description:Infinite Bounce Balls + code:7E594C:05 + +cartridge sha256:0773eb741ce28f963f767fc7dd44678eb3d37ed4dc7fc82bb9cce7d55f1cfc64 + title:Mickey Mania - The Timeless Adventures of Mickey Mouse (USA) + cheat + description:Infinite health + code:C2B8-CAC3 + cheat + description:Infinite lives + code:C2B3-C313 + cheat + description:Infinite Marbles + code:C2A8-CA32 + cheat + description:Each Marble worth 99 + code:CB8C-C27A + cheat + description:One hit and you're dead + code:DDAA-3869 + cheat + description:Start with less health + code:D4AA-3869 + cheat + description:Start with more health + code:DBAA-3869 + cheat + description:Start with 1 life + code:DDA3-36D9 + cheat + description:Start with 7 lives + code:D1A3-36A9 + cheat + description:Start with 10 lives + code:DBA3-36A9 + cheat + description:Start on stage - the Wharf + code:DFAB-3669 + cheat + description:Start on stage - Mad Doc 1 + code:D4AB-3669 + cheat + description:Start on stage - Mad Doc 2 + code:D7AB-3669 + cheat + description:Start on stage - Ride The Gurney + code:D0AB-3669 + cheat + description:Start on stage - Mad Doc 4 + code:D9AB-3669 + cheat + description:Start on stage - Elevator + code:D1AB-3669 + cheat + description:Start on stage - Mad Doc Eol + code:D5AB-3669 + cheat + description:Start on stage - Moose Hunt + code:D6AB-3669 + cheat + description:Start on stage - Moose Chase + code:DBAB-3669 + cheat + description:Start on stage - Haunted House + code:DCAB-3669 + cheat + description:Start on stage - Haunted Basement + code:D8AB-3669 + cheat + description:Start on stage - Haunted Halls + code:DAAB-3669 + cheat + description:Start on stage - Garden + code:D2AB-3669 + cheat + description:Start on stage - Tunnel + code:D3AB-3669 + cheat + description:Start on stage - Steps + code:DEAB-3669 + cheat + description:Start on stage - Table + code:FDAB-3669 + cheat + description:Start on stage - Library + code:FFAB-3669 + cheat + description:Start on stage - Kitchen + code:F4AB-3669 + cheat + description:Start on stage - Dungeon + code:F7AB-3669 + cheat + description:Start on stage - Tower Escape + code:F0AB-3669 + cheat + description:Start on stage - Dungeon 2 + code:F9AB-3669 + +cartridge sha256:453359b20f78787fcfea0dafe715238f0ff3f1d6f4d729285dc72a8004131a3b + title:Mickey to Donald - Magical Adventure 3 (Japan) + cheat + description:Invincibility - P1 + code:7E0454:FF + cheat + description:Invincibility - P2 + code:7E0554:FF + cheat + description:Infinite health - P1 + code:7E046F:03 + cheat + description:Infinite health - P2 + code:7E056F:03 + cheat + description:Infinite lives - P1 + code:7E0486:04 + cheat + description:Infinite lives - P2 + code:7E0586:04 + cheat + description:Infinite Oxygen - P1 + code:7E0481:0F + cheat + description:Infinite Oxygen - P2 + code:7E0581:0F + cheat + description:Max power bar - P1 + code:7E048A:FF + cheat + description:Max power bar - P2 + code:7E058A:FF + +cartridge sha256:a2adeb4bf0e7cc943611ac726e5578da404373a79e91436c9bbd15480688b15c + title:Micro Machines (USA) + cheat + description:Infinite lives + code:7E0323:09 + +cartridge sha256:889beb58d2a48a05a6230cabda14555cb030e2e986c0293bdf396e85af5c6798 + title:Mighty Max (USA) + cheat + description:Invincibility + code:7E0254:A1 + cheat + description:Infinite energy + code:7E0294:03 + cheat + description:Infinite lives + code:7E028C:09 + +cartridge sha256:624a66607caef2ca34920ea15b84b28cdd1916ee089d496cec4f1d43621fdbb3 + title:Mighty Morphin Power Rangers (USA) + cheat + description:Invincibility + code:C280-AD2F + cheat + description:Infinite health + code:C286-6DF4 + cheat + description:Infinite lives + code:3CAA-DFDF + cheat + description:Infinite bombs on pick-up + code:C2B7-0FF7 + cheat + description:Mega-jump + code:EC6A-ADF7 + cheat + description:More health from capsule + code:AD64-6465 + cheat + description:Trini moves faster before morphing + code:D468-04BF + cheat + description:Billy moves faster before morphing + code:D46C-0DBF + cheat + description:Jason moves faster before morphing + code:D46B-04BF + cheat + description:Kimberley moves faster before morphing + code:AD6C-049F + cheat + description:Zach moves faster before morphing + code:D468-0DBF + cheat + description:Trini moves faster after morphing + code:EE62-0DBF + cheat + description:Billy moves faster after morphing + code:EE6A-049F + cheat + description:Jason moves faster after morphing + code:D46A-0D9F + cheat + description:Kimberley moves faster after morphing + code:AD62-0D9F + cheat + description:Zach moves faster, but the wrong way + code:EE62-04BF + cheat + description:Start game with full health + code:AD82-64DD + cheat + description:Start with 1 life + code:DD8A-6DDD + cheat + description:Start with 6 lives + code:D98A-6DDD + cheat + description:Start with 9 lives + code:D68A-6DDD + cheat + description:Infinite health (Megazord) + code:7E04C0:71 + cheat + description:Infinite power (Megazord) + code:7E04C2:71 + +cartridge sha256:1b85c0690aa156a255c7f79e133e453345452698fa98abf8df744c262d0cf865 + title:Mighty Morphin Power Rangers - The Fighting Edition (USA) + cheat + description:Infinite health - P1 + code:7E1A22:70 + cheat + description:Infinite health - P2 + code:7E1A26:70 + cheat + description:Special maxed - P1 + code:7E06A0:30 + cheat + description:Special maxed -P2 + code:7E06A6:30 + cheat + description:Play As Ivan Ooze - P1 + code:7E1A68:10 + cheat + description:Play as Ivan Ooze - P2 + code:7E1A6C:10 + cheat + description:Infinite round time + code:7E06B8:06+7E06BA:00 + cheat + description:Infinite time + code:7E06BC:01 + cheat + description:Special 1 - P1 + code:7E1B00:07+7E1B02:0C + cheat + description:Special 2 - P1 + code:7E1B08:07+7E1B0A:0C + cheat + description:Special 3 - P1 + code:7E1B10:07+7E1B12:0C + cheat + description:Special 4 - P1 + code:7E1B18:07+7E1B1A:0C + cheat + description:Special 5 - P1 + code:7E1B20:07+7E1B22:0C + cheat + description:Special 1 - P2 + code:7E1B04:07+7E1B06:0C + cheat + description:Special 2 - P2 + code:7E1B0C:07+7E1B0E:0C + cheat + description:Special 3 - P2 + code:7E1B14:07+7E1B16:0C + cheat + description:Special 4 - P2 + code:7E1B1C:07+7E1B1E:0C + cheat + description:Special 5 - P2 + code:7E1B24:07+7E1B26:0C + cheat + description:Super move - P2 + code:7E1B34:03+7E1B36:18 + +cartridge sha256:c706b70097c679f6f0ced6f77a30620807d0b2555fc3c683c0ec2fc791176039 + title:Mighty Morphin Power Rangers - The Movie (USA) + cheat + description:Invincibility + code:6286-D46A + cheat + description:Infinite life force + code:C226-07A2 + cheat + description:Almost infinite life force + code:8B26-07A2 + cheat + description:Infinite lives + code:C229-0D6A + cheat + description:Infinite continues - 1P mode + code:C2E0-DF0A + cheat + description:Infinite continues - 2P mode + code:C2B1-AFAA + cheat + description:Large main power-up box gives max power + code:F620-0FA2 + cheat + description:Main collectable power doesn't go down after ranger powerup as fast + code:3C8D-6D67+3CA4-64DA + cheat + description:One hit kills + code:6D27-AD6A + cheat + description:No continues + code:DDA8-0DDD + cheat + description:Start with mega-points + code:D7AA-0DDD + cheat + description:Start with a lot of energy - first life only + code:DBA2-04AD + cheat + description:Start with very little energy - first life only + code:DFA2-04AD + cheat + description:Start with very little energy after first life + code:DF29-07DA + cheat + description:Start with more energy after first life + code:DB29-07DA + cheat + description:Start with 9 continues + code:DBA8-0DDD + cheat + description:Start with 9 lives + code:DB6E-0D6D + cheat + description:Start with 5 lives + code:D96E-0D6D + cheat + description:Start with 1 life + code:DF6E-0D6D + cheat + description:Invincibility - P1 + code:7E1C28:01 + cheat + description:Infinite health - P1 + code:7E0628:05 + cheat + description:Infinite power - P1 + code:7E062A:18 + cheat + description:Infinite time - P1 + code:FF4139:09 + cheat + description:Infinite lives - P1 + code:7E060A:09 + +cartridge sha256:2828e4485357585714f16f5bf96910794e22e4dfd19f2a22ce20d0a599f25878 + title:Miracle Girls (Japan) + cheat + description:Invincibility + code:1D3F-E4AD + cheat + description:Infinite lives + code:C243-7707 + +cartridge sha256:8715a641f2e4dd8b6066be7f2683d9129fff3fcccaf0a09cc8bdd2aa56460764 + title:Mohawk & Headphone Jack (USA) + cheat + description:Infinite health + code:7E0308:03 + cheat + description:Infinite lives + code:7E0306:05 + +cartridge sha256:6b0ac4d52d24536cdb7d9d0dc7d19ee30d08ac34363983290c5912ccc850fa0d + title:Monopoly (USA) (Rev 1) + cheat + description:Land, rent and some other things are free - all players + code:1D85-6FDF + cheat + description:Land, rent, and some other things are $50 - all players + code:3B85-6FDF+7485-6F0F+DD85-6F6F + cheat + description:Land, rent, and some other things are $100 - all players + code:3B85-6FDF+1085-6F0F+DD85-6F6F + cheat + description:Land, rent, and some other things are $200 - all players + code:3B85-6FDF+A685-6F0F+DD85-6F6F + cheat + description:Land, rent, and some other things are $500 - all players + code:3B85-6FDF+E085-6F0F+DD85-6F6F + cheat + description:Always throw double 6's + code:CBB3-AF0D+D1B3-AF6D+D1B3-AFAD + cheat + description:Always throw double 5's + code:CBB3-AF0D+D9B3-AF6D+D9B3-AFAD + cheat + description:Always throw double 4's + code:CBB3-AF0D+D0B3-AF6D+D0B3-AFAD + cheat + description:Always throw double 3's + code:CBB3-AF0D+D4B3-AF6D+D7B3-AFAD + cheat + description:Always throw double 2's + code:CBB3-AF0D+D4B3-AF6D+D4B3-AFAD + cheat + description:Always throw double 1's + code:CBB3-AF0D+DFB3-AF6D+DFB3-AFAD + cheat + description:P1 has a Get Out Of Jail card + code:7E08F2:01 + cheat + description:P2 has a Get Out Of Jail card + code:7E08F4:01 + cheat + description:P3 has a Get Out Of Jail card + code:7E08F6:01 + cheat + description:P4 has a Get Out Of Jail card + code:7E08F8:01 + cheat + description:P5 has a Get Out Of Jail card + code:7E08FA:01 + cheat + description:P6 has a Get Out Of Jail card + code:7E08FC:01 + cheat + description:P7 has a Get Out Of Jail card + code:7E08FE:01 + cheat + description:P8 has a Get Out Of Jail card + code:7E0900:01 + +cartridge sha256:480ae7186fd5b28200cd88e136b9cd3b6600d32508e280a0bc27ea0ed8d3c0bb + title:Monopoly (USA) + cheat + description:Land, rent and some other things are free - all players + code:1D85-6FDF + cheat + description:Land, rent, and some other things are $50 - all players + code:3B85-6FDF+7485-6F0F+DD85-6F6F + cheat + description:Land, rent, and some other things are $100 - all players + code:3B85-6FDF+1085-6F0F+DD85-6F6F + cheat + description:Land, rent, and some other things are $200 - all players + code:3B85-6FDF+A685-6F0F+DD85-6F6F + cheat + description:Land, rent, and some other things are $500 - all players + code:3B85-6FDF+E085-6F0F+DD85-6F6F + cheat + description:Always throw double 6's + code:CBB3-AF0D+D1B3-AF6D+D1B3-AFAD + cheat + description:Always throw double 5's + code:CBB3-AF0D+D9B3-AF6D+D9B3-AFAD + cheat + description:Always throw double 4's + code:CBB3-AF0D+D0B3-AF6D+D0B3-AFAD + cheat + description:Always throw double 3's + code:CBB3-AF0D+D4B3-AF6D+D7B3-AFAD + cheat + description:Always throw double 2's + code:CBB3-AF0D+D4B3-AF6D+D4B3-AFAD + cheat + description:Always throw double 1's + code:CBB3-AF0D+DFB3-AF6D+DFB3-AFAD + cheat + description:P1 has a Get Out Of Jail card + code:7E08F2:01 + cheat + description:P2 has a Get Out Of Jail card + code:7E08F4:01 + cheat + description:P3 has a Get Out Of Jail card + code:7E08F6:01 + cheat + description:P4 has a Get Out Of Jail card + code:7E08F8:01 + cheat + description:P5 has a Get Out Of Jail card + code:7E08FA:01 + cheat + description:P6 has a Get Out Of Jail card + code:7E08FC:01 + cheat + description:P7 has a Get Out Of Jail card + code:7E08FE:01 + cheat + description:P8 has a Get Out Of Jail card + code:7E0900:01 + +cartridge sha256:3c6d3e4a9c9af160f1c1cf11ce4ead531d9500c1f58f1cbe682c90a5eaa3efb2 + title:Mortal Kombat (USA) + cheat + description:Invincibility (except against throws) + code:40C2-4FDF+40C2-446F+3DC2-476F+55C2-47AF+F5C3-4DDF+1DB9-34AF + cheat + description:Infinite health + code:CF30-CFAF+6230-C40F+8B30-C46F + cheat + description:Infinite time + code:C9B2-17AF + cheat + description:Have much more fatality time + code:5EB5-3F64 + cheat + description:Always get Flawless Victory bonus + code:6DB8-3D67 + cheat + description:First strike of any kind wins round + code:DDBC-370F + cheat + description:Hit anywhere - P1 + code:3DBF-3D0F+27BF-3D6F+F6BF-3DAF+74BF-3F0F + cheat + description:All strikes do minimal damage (all equal to 1 hit point) (2P game only, donï¾’t choose handicap for either player) + code:DDBF-1FA4 + cheat + description:P1 nearly invincible in 2P game (go to options, move P1ï¾’s handicap bar all the way to the right) + code:D881-404F + cheat + description:All throws do more damage + code:56B9-4DAD + cheat + description:Kano's High Punch does more damage + code:F320-1914 + cheat + description:Kano's Low Punch does more damage + code:F320-15C4 + cheat + description:Kano's High Kick does more damage + code:0626-1514 + cheat + description:Kano's Low Kick does more damage + code:062B-19C4 + cheat + description:Kano's Head Blow does more damage + code:0621-1044 + cheat + description:Kano's Knee does more damage + code:0629-1934 + cheat + description:Kano's Crouched Kick does more damage + code:7A26-1944 + cheat + description:Kano's Uppercut does more damage + code:5625-1134 + cheat + description:Kano's Roundhouse Kick does more damage + code:1D27-1544 + cheat + description:Kano's Foot Sweep does more damage + code:7A25-10C4 + cheat + description:Kano's Flying Punch does more damage + code:082C-1144 + cheat + description:Kano's Knife does more damage (only at close distance) + code:0824-11C4 + cheat + description:Johnny Cage's High Punch does more damage + code:F32C-4944 + cheat + description:Johnny Cage's Low Punch does more damage + code:F32C-4514 + cheat + description:Johnny Cage's High Kick does more damage + code:062B-40C4 + cheat + description:Johnny Cage's Low Kick does more damage + code:042B-4134 + cheat + description:Johnny Cage's Head Blow does more damage + code:7A2A-4144 + cheat + description:Johnny Cage's Knee does more damage + code:0622-4014 + cheat + description:Johnny Cage's Crouched Kick does more damage + code:F628-4534 + cheat + description:Johnny Cage's Uppercut does more damage + code:5622-41C4 + cheat + description:Johnny Cage's Roundhouse Kick does more damage + code:1D26-4114 + cheat + description:Johnny Cage's Foot Sweep does more damage + code:7A28-49C4 + cheat + description:Johnny Cage's Flying Punch does more damage + code:0826-4044 + cheat + description:Johnny Cage's Shadow Kick does more damage + code:9C20-41C4 + cheat + description:Johnny Cage's Fireball does more damage (only at close distance) + code:0821-4914 + cheat + description:Johnny Cage's Split Punch does more damage + code:1129-4544 + cheat + description:Liu Kang's High Punch does more damage + code:F323-C034 + cheat + description:Liu Kang's Low Punch does more damage + code:F323-C544 + cheat + description:Liu Kang's High Kick does more damage + code:0624-30C4 + cheat + description:Liu Kang's Low Kick does more damage + code:0624-3134 + cheat + description:Liu Kang's Head Blow does more damage + code:7A28-C534 + cheat + description:Liu Kang's Knee does more damage + code:062E-C914 + cheat + description:Liu Kang's Crouched Kick does more damage + code:7A2F-3114 + cheat + description:Liu Kang's Uppercut does more damage + code:562F-3044 + cheat + description:Liu Kang's Roundhouse Kick does more damage + code:1D22-C1C4 + cheat + description:Liu Kang's Foot Sweep does more damage + code:7A2D-3934 + cheat + description:Liu Kang's Flying Punch does more damage + code:0827-3514 + cheat + description:Liu Kang's Special Flying Kick does more damage + code:9C28-C9C4 + cheat + description:Liu Kang's Fireball does more damage (only at close distance) + code:082A-C144 + cheat + description:Sonya Blade's High Punch does more damage + code:F32F-393F + cheat + description:Sonya Blade's Low Punch does more damage + code:F324-304F + cheat + description:Sonya Blade's High Kick does more damage + code:9023-C01F + cheat + description:Sonya Blade's Low Kick does more damage + code:9F23-C1CF + cheat + description:Sonya Blade's Head Blow does more damage + code:7A2E-C03F + cheat + description:Sonya Blade's Knee does more damage + code:062E-C54F + cheat + description:Sonya Blade's Crouched Kick does more damage + code:7A2D-35CF + cheat + description:Sonya Blade's Uppercut does more damage + code:5624-311F + cheat + description:Sonya Blade's Roundhouse Kick does more damage + code:1122-C14F + cheat + description:Sonya Blade's Foot Sweep does more damage + code:7A2A-C53F + cheat + description:Sonya Blade's Flying Punch does more damage + code:0827-313F + cheat + description:Sonya Blade's Leg Grab does more damage + code:5620-17A7 + cheat + description:Sonya Blade's Sonic Rings does more damage (only at close distance) + code:0822-C13F + cheat + description:Sonya Blade's Special Flying Kick does more damage + code:0827-313F + cheat + description:Rayden's High Punch does more damage + code:F324-C914 + cheat + description:Rayden's Low Punch does more damage + code:F327-C934 + cheat + description:Rayden's High Kick does more damage + code:092F-C034 + cheat + description:Rayden's Low Kick does more damage + code:042F-C544 + cheat + description:Rayden's Head Blow does more damage + code:7A29-C0C4 + cheat + description:Rayden's Knee does more damage + code:0629-C134 + cheat + description:Rayden's Crouched Kick does more damage + code:F620-C114 + cheat + description:Rayden's Uppercut does more damage + code:5621-C944 + cheat + description:Rayden's Roundhouse Kick does more damage + code:9C2D-C1C4 + cheat + description:Rayden's Foot Sweep does more damage + code:7A20-C044 + cheat + description:Rayden's Flying Punch does more damage + code:082D-C014 + cheat + description:Rayden's Flying Thunderbolt does more damage + code:9C22-1514 + cheat + description:Rayden's Lightning does more damage (only at close distance) + code:0823-19C4 + cheat + description:Scorpion's, Sub-Zero's and Reptile's High Punch do more damage + code:F328-3934 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Low Punch do more damage + code:F32A-3044 + cheat + description:Scorpion's, Sub-Zero's and Reptile's High Kick do more damage + code:062E-39C4 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Low Kick do more damage + code:062E-3534 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Head Blow do more damage + code:7A22-30C4 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Knee do more damage + code:062A-3114 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Crouched Kick do more damage + code:F62F-41C7 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Uppercut do more damage + code:562C-35C4 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Roundhouse Kick do more damage + code:1D2F-4017 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Foot Sweep do more damage + code:7A2D-4147 + cheat + description:Scorpion's, Sub-Zero's and Reptile's Flying Punch do more damage + code:0823-3944 + cheat + description:Sub-Zero's and Reptile's Deep Freeze do damage + code:462C-3914 + cheat + description:Sub-Zero's and Reptile's Slide do more damage + code:4525-3144 + cheat + description:Scorpion's and Reptile's Harpoon do more damage + code:F626-31C4 + cheat + description:Scorpion's and Reptile's Scorpion Split do more damage + code:0823-3944 + cheat + description:Each round is 199 seconds (time counts down twice) + code:D466-3D04 + cheat + description:Each round is 90 seconds + code:BF66-3DD4+DD66-3D04 + cheat + description:Each round is 80 seconds + code:6F66-3DD4+DD66-3D04 + cheat + description:Each round is 70 seconds + code:5F66-3DD4+DD66-3D04 + cheat + description:Each round is 60 seconds + code:1F66-3DD4+DD66-3D04 + cheat + description:Each round is 50 seconds + code:9F66-3DD4+DD66-3D04 + cheat + description:Each round is 40 seconds + code:0F66-3DD4+DD66-3D04 + cheat + description:Each round is 30 seconds + code:7F66-3DD4+DD66-3D04 + cheat + description:Each round is 20 seconds + code:4F66-3DD4+DD66-3D04 + cheat + description:Each round is 10 seconds + code:FF66-3DD4+DD66-3D04 + cheat + description:Always fight in the the Courtyard + code:DD6A-47AF + cheat + description:After 1st match, almost always fight at the Palace Gates + code:CB6A-44AF+DF6A-47DF + cheat + description:After 1st match, almost always fight in the Warrior Shrine + code:CB6A-44AF+D46A-47DF + cheat + description:After 1st match, almost always fight in the Pit + code:CB6A-44AF+D76A-47DF + cheat + description:After 1st match, almost always fight in the Throne Room + code:CB6A-44AF+D06A-47DF + cheat + description:After 1st match, almost always fight in Goro's Lair + code:CB6A-44AF+D96A-47DF + cheat + description:After 1st match, almost always fight in the bottom of the pit (screen says Goro's Lair) + code:CB6A-44AF+D16A-47DF + cheat + description:Almost always fight Johnny Cage + code:CBBA-394F+DDBA-391F + cheat + description:Almost always fight Kano + code:CBBA-394F+DFBA-391F + cheat + description:Almost always fight Rayden + code:CBBA-394F+D4BA-391F + cheat + description:Almost always fight Liu Kang + code:CBBA-394F+D7BA-391F + cheat + description:Almost always fight Scorpion + code:CBBA-394F+D0BA-391F + cheat + description:Almost always fight Sub-Zero + code:CBBA-394F+D9BA-391F + cheat + description:Almost always fight Sonya Blade + code:CBBA-394F+D1BA-391F + cheat + description:Almost always fight Goro (don't use Kano's or Johnny Cage's finishing move on Goro) + code:CBBA-394F+D5BA-391F + cheat + description:Start on Match 2 + code:DF61-14DD + cheat + description:Start on Match 3 + code:D461-14DD + cheat + description:Start on Match 4 + code:D761-14DD + cheat + description:Start on Match 5 + code:D061-14DD + cheat + description:Start on Match 6 + code:D961-14DD + cheat + description:Start on Mirror Match + code:D161-14DD + cheat + description:Start on Endurance 1 match + code:D561-14DD + cheat + description:Start on Endurance 2 match + code:D661-14DD + cheat + description:Start on Endurance 3 match + code:DB61-14DD + cheat + description:Start on match with Goro + code:DC61-14DD + cheat + description:Start on match with Shang Tsung + code:D861-14DD + +cartridge sha256:6caa0ab221a3e690a104baa4935fc86dbc385d4272e88afb46b999bf6c6edb36 + title:Mortal Kombat - Shinken Kourin Densetsu (Japan) + cheat + description:Infinite health + code:CF31-4F64+6231-44D4+EB31-4404+D031-4464 + cheat + description:One hit kill - P1 + code:DD3C-44D4+623C-4464+E83C-44A4+D03C-47D4 + +cartridge sha256:43e36a74fb73a7efc46b380599e269b1fff8f55ecf80f5cf50c34d02ceda041a + title:Mortal Kombat II (USA) + cheat + description:Invincibility - P1 + code:C2B1-14F7 + cheat + description:Invincibility - P2/CPU + code:C2B5-14F7 + cheat + description:Infinite health + code:CB89-4FAA+CF89-44DA+DD89-440A+EA89-44AA+4389-47DA + cheat + description:Infinite time + code:6DC7-1DAA + cheat + description:Infinite continues + code:C2C4-47AA + cheat + description:No health - P1 + code:DDB1-1FF7 + cheat + description:No health - P2/CPU + code:DDB5-1FF7 + cheat + description:Hit anywhere - P1 + code:0DB0-4F97+2DB0-4FF7+3DB0-4D97+DDB0-4DB7 + cheat + description:Have 127x more fatality time + code:5EC2-CF02 + cheat + description:Disable throws - 2P mode + code:622B-C7AC + cheat + description:Mileena's Sai Throw does massive damage + code:06E1-17D4 + cheat + description:Liu Kang's High Fireball does massive damage + code:06E9-1DD7 + cheat + description:Kung Lao's Hat Throw does massive damage + code:06E2-1767 + cheat + description:Cage's Shadow Kick does massive damage + code:06EF-4767 + cheat + description:Reptile's Force Ball does massive damage + code:06EB-17AF + cheat + description:Shang Tsung's Flaming Skull attack does massive damage + code:06E0-4FA4 + cheat + description:Kitana's Fan Throw does massive damage + code:06E9-17A4 + cheat + description:Baraka's Blade Spark does massive damage + code:06EE-C4A4 + cheat + description:Rayden's Lightning Bolt does massive damage + code:06E4-34DF + cheat + description:Enable all 2P rules/moves when fighting computer + code:6DCF-4D9D + cheat + description:Always fight Kung Lao + code:CBC6-3D6E+DDC6-3DAE + cheat + description:Always fight Liu Kang + code:CBC6-3D6E+DFC6-3DAE + cheat + description:Always fight Cage + code:CBC6-3D6E+D4C6-3DAE + cheat + description:Always fight Baraka + code:CBC6-3D6E+D7C6-3DAE + cheat + description:Always fight Kitana + code:CBC6-3D6E+D0C6-3DAE + cheat + description:Always fight Mileena + code:CBC6-3D6E+D9C6-3DAE + cheat + description:Always fight Shang Tsung + code:CBC6-3D6E+D1C6-3DAE + cheat + description:Always fight Rayden + code:CBC6-3D6E+D5C6-3DAE + cheat + description:Always fight Sub-Zero + code:CBC6-3D6E+D6C6-3DAE + cheat + description:Always fight Reptile + code:CBC6-3D6E+DBC6-3DAE + cheat + description:Always fight Scorpion + code:CBC6-3D6E+DCC6-3DAE + cheat + description:Always fight Jax + code:CBC6-3D6E+D8C6-3DAE + cheat + description:Always fight Kintaro + code:CBC6-3D6E+DAC6-3DAE + cheat + description:Always fight Shao Kahn + code:CBC6-3D6E+D2C6-3DAE + cheat + description:Always fight Smoke + code:CBC6-3D6E+D3C6-3DAE + cheat + description:Always fight Noob Saibot + code:CBC6-3D6E+DEC6-3DAE + cheat + description:Always fight Jade + code:CBC6-3D6E+FDC6-3DAE + cheat + description:Start with 0 continues + code:DF8C-CDDA + cheat + description:Start with 2 continues + code:D78C-CDDA + cheat + description:Start with 6 continues + code:D58C-CDDA + cheat + description:Start with 8 continues + code:DB8C-CDDA + cheat + description:Invincibility - P1 (alt) + code:849C68:80+849C69:09+849C7B:00+85AA52:60+85AB1C:60+85AC2A:60 + cheat + description:Invincibility - P2/CPU (alt) + code:849C68:80+849C69:06+849C76:00+85AA52:60+85AB1C:60+85AC2A:60 + +cartridge sha256:ca2f86ca77f822fcd8e86f5a287f2a76d0becbb81a7bce73ae22909beb2f834c + title:Mortal Kombat II (USA) (Rev 1) + cheat + description:P1 is killed by one hit + code:DDB1-1FF7 + cheat + description:P2/CPU is killed by one hit + code:DDB5-1FF7 + cheat + description:Have 127x more fatality time + code:5EC3-CF02 + cheat + description:Disable throws - 2P mode + code:622B-C7AC + cheat + description:Enable all 2P rules/moves when fighting computer + code:6DCF-4D9D + +cartridge sha256:417874aa57856fe93eefdb24066fa1a9ca3f23c72c09d5247ae2b3ab4b3d09d1 + title:Mortal Kombat 3 (USA) + cheat + description:Infinite health - P1 + code:C230-CD62 + cheat + description:Infinite health - P2 + code:C239-CD62 + cheat + description:P1 takes all damage + code:DD37-CF62 + cheat + description:P2 takes all damage + code:6D37-CF02 + cheat + description:Infinite continues + code:A220-3FB6 + cheat + description:Hit anywhere - P1 + code:3DE6-3DDE+6D30-1462+C4E6-3F6E+D4E6-3D0E+DDE6-3D6E+EDE6-3DAE+D7E6-3FDE+EE30-14A2+0AE6-3F0E+0AE6-340E+0AE6-34DE+39E6-346E+39E6-3FAE + cheat + description:Press A on main menu for Sound Test + code:D42E-44D8 + cheat + description:Press Up on main menu for Kool Stuff Menu + code:D424-17D8 + cheat + description:Press Select on main menu for Kooler Stuff Menu + code:D421-1DD8 + cheat + description:Press X on main menu for Scott's Menu + code:D42B-1FD8 + cheat + description:Always fight Kano in Master mode + code:CE8F-3FB7+BA23-3727+DDAE-4FFF + cheat + description:Always fight Sonya in Master mode + code:CE8F-3FB7+BA23-3727+DFAE-4FFF + cheat + description:Always fight Jax in Master mode + code:CE8F-3FB7+BA23-3727+D4AE-4FFF + cheat + description:Always fight Nightwolf in Master mode + code:CE8F-3FB7+BA23-3727+D7AE-4FFF + cheat + description:Always fight Sub-Zero in Master mode + code:CE8F-3FB7+BA23-3727+D0AE-4FFF + cheat + description:Always fight Stryker in Master mode + code:CE8F-3FB7+BA23-3727+D9AE-4FFF + cheat + description:Always fight Sindel in Master mode + code:CE8F-3FB7+BA23-3727+D1AE-4FFF + cheat + description:Always fight Sektor in Master mode + code:CE8F-3FB7+BA23-3727+D5AE-4FFF + cheat + description:Always fight Cyrax in Master mode + code:CE8F-3FB7+BA23-3727+D6AE-4FFF + cheat + description:Always fight Kung Lao in Master mode + code:CE8F-3FB7+BA23-3727+DBAE-4FFF + cheat + description:Always fight Kabal in Master mode + code:CE8F-3FB7+BA23-3727+DCAE-4FFF + cheat + description:Always fight Sheeva in Master mode + code:CE8F-3FB7+BA23-3727+D8AE-4FFF + cheat + description:Always fight Shang Tsung in Master mode + code:CE8F-3FB7+BA23-3727+DAAE-4FFF + cheat + description:Always fight Liu Kang in Master mode + code:CE8F-3FB7+BA23-3727+D2AE-4FFF + cheat + description:Always fight Smoke in Master mode + code:CE8F-3FB7+BA23-3727+D3AE-4FFF + cheat + description:Always fight Motaro in Master mode + code:CE8F-3FB7+BA23-3727+DEAE-4FFF + cheat + description:Always fight Shao Kahn in Master mode + code:CE8F-3FB7+BA23-3727+FDAE-4FFF + cheat + description:Always fight Noob-Saibot in Master mode + code:CE8F-3FB7+BA23-3727+FFAE-4FFF + cheat + description:Invincibility (except throws and uppercuts) - P1 + code:7E5447:01 + cheat + description:Invincibility (except throws and uppercuts) - P2 + code:7E5449:01 + cheat + description:First round / one button fatalities + code:7E3AF0:01 + +cartridge sha256:340293c06536d7b6981ad7c681e404f4390ff6c62340f844a4558877c1b82af0 + title:Mr. Do! (USA) + cheat + description:Infinite lives + code:7E18B2:09 + cheat + description:Two enemies on screen at most + code:7E1440:00 + cheat + description:Level modifier (level is always one less than entered) + code:7E189E:??+7E18A0:??+7E18B4:?? + +cartridge sha256:3472dd574b50aed2fa998f464398db4fbb00f5a300a672c3737ee9336a008a16 + title:Mr. Nutz (USA) (En,Fr) + cheat + description:Invincibility + code:7E008D:2D + cheat + description:Infinite Nuts + code:7E0A29:99 + cheat + description:Infinite coins + code:7E1894:99 + cheat + description:One hit kills on bosses + code:7E05D0:00 + +cartridge sha256:4f172253946ae29ddbf1e8169b48d55fe1aed8d007adafc6fa3e62685ed45de0 + title:Mr. Tuff (USA) (En,Fr,De) (Proto) (1994-07-12) + cheat + description:Invincibility + code:7EEB46:FE + cheat + description:Infinite health + code:7ED580:03 + cheat + description:Infinite lives + code:7ED580:03 + cheat + description:No targets to smash + code:7EEB2E:00 + +cartridge sha256:007735e68a91cab403f1c955d9d562e9311124e660fa5b32e5c5d0a2e052160e + title:Ms. Pac-Man (USA) + cheat + description:Ghosts eatable at start and infinite power pill time + code:7E029E:03 + cheat + description:Infinite Power Pellet time + code:7E029E:01 + cheat + description:Infinite lives + code:7E028C:03 + cheat + description:Level modifier + code:7E039E:?? + +cartridge sha256:f292598ac462fdfcd32ad9b6b35ac01d4bab020391dff92bfe94780ec604289a + title:Musya (USA) + cheat + description:Infinite health + code:7E101A:10 + cheat + description:Infinite lives + code:7E1033:03 + cheat + description:Infinite Fire magic + code:7E102F:04 + cheat + description:Infinite Heal magic + code:7E1032:33 + cheat + description:Infinite Help magic + code:7E1030:33 + cheat + description:Infinite Lightning magic + code:7E102E:04 + cheat + description:Infinite Web magic + code:7E1031:33 + +cartridge sha256:a19337da953f63c806754b90af7ff9fbea1bf090618dae732ee3a546882b8700 + title:Mystic Ark (Japan) + cheat + description:999 HP for hero + code:7EB004:0F+7EB005:27 + cheat + description:999 MP for Hero + code:7EB008:E7+7EB009:03 + cheat + description:Have enough gold + code:7EB120:FF+7EB121:FF + cheat + description:Quick gain EXP + code:7E0551:FF+7E0552:FF + +cartridge sha256:c70b812a9d2df7f95b279e4050e03a4b8a68588a370816e645f378296b84e5d1 + title:NBA All-Star Challenge (USA) + cheat + description:P1 can't score in the 1-on-1, free throw or tournament stages + code:123B-3F0D + cheat + description:P2 or computer can't score in the 1-on-1, free throw or tournament events + code:A238-340D + cheat + description:P1 can't score in 3-point shootout + code:A239-1F0D+A237-176D + cheat + description:P2 or computer can't score in 3-point shootout + code:A23F-176D+A23D-1FAD + cheat + description:Stop shot clock (1-on-1 and 1-on-1 tournament modes) + code:A2C6-3F07+6DC6-3DA7 + cheat + description:12-second shot clock (1-on-1 and 1-on-1 tournament modes) + code:DFC3-34D7+D4C3-3DA7 + cheat + description:48-second shot clock - after the 1st shot (1-on-1 and 1-on-1 tournament modes) + code:D0C3-34D7+D6C3-3DA7 + +cartridge sha256:b257cffb3484e6be051a56268cb99ee888bd6d3e9c0e8d6d0779ff66c411f6ba + title:NBA Jam - Tournament Edition (USA) + cheat + description:Infinite shot clock time + code:C2C9-1467 + cheat + description:Ability to set shot clock option down to 1 + code:DF62-1B1B + cheat + description:Have almost Infinite Turbo - P1 + code:C28B-1DA5 + cheat + description:Have almost Infinite Turbo - P2 + code:C286-1B2B + cheat + description:Turbo recharges quicker - P1 + code:DF8A-1D65 + cheat + description:Turbo recharges quicker - P2 + code:DF88-1BBB + cheat + description:Twice as much turbo - P1 + code:0D8A-1FA5 + cheat + description:Twice as much turbo - P2 + code:0D88-1C2B + cheat + description:Shots worth more - P1 + code:76C2-6DDF + cheat + description:Shots worth more - P2 + code:76C3-DF04 + cheat + description:Player is On Fire after 2 baskets instead of 3 + code:D0BF-11C8 + cheat + description:No turbo (except in tournament mode) - P1 + code:CB88-1565 + cheat + description:No turbo (except in tournament mode) - P2 + code:CB88-16BB + cheat + description:Move much faster (except in tournament mode) - all players + code:DDE4-0B28+D1E4-08F8 + cheat + description:Move super fast (except in tournament mode) - all players + code:DDE4-0B28+DBE4-08F8 + cheat + description:Hot spots and Power ups are on in tournament mode automatically (don't select the special features menu) + code:D1E9-DC98 + cheat + description:Have all secret power-ups except slippery floors on - all players + code:DDE5-C74C+6DEB-CD4C+41E5-F47D + cheat + description:Have Power Push, Powered Up 3pts, Infinite Turbo, Always On Fire, Super Dunks, Max Power, Powered Up Goal Tending and Quick Hands - P1 + code:EEEA-1FDC + cheat + description:Have Power Block, Powered Up 3pts, Infinite Turbo, Always On Fire, Super Dunks, Max Power, Powered Up Goal Tending and Quick Hands - P2 + code:EEE1-C46C + cheat + description:Have Power Block, Powered Up 3pts, Infinite Turbo, Always On Fire, Super Dunks, Max Power, Powered Up Goal Tending and Quick Hands - P3 + code:EEEF-3DDC + cheat + description:Have Power Block, Powered Up 3pts, Infinite Turbo, Always On Fire, Super Dunks, Max Power, Powered Up Goal Tending and Quick Hands - P4 + code:EEE8-3F6C + cheat + description:Have Power-up offense, Speed Up, block opponent to make both fall, Teleport Pass and High Shots - P1 + code:EEEA-1F0C + cheat + description:Have Power-up offense, Speed Up, block opponent to make both fall, Teleport Pass and High Shots - P2 + code:EEE1-C4AC + cheat + description:Have Power-up offense, Speed Up, block opponent to make both fall, Teleport Pass and High Shots - P3 + code:EEEF-3D0C + cheat + description:Have Power-up offense, Speed Up, block opponent to make both fall, Teleport Pass and High Shots - P4 + code:EEE8-3FAC + cheat + description:Have all secret power-ups - all players + code:DDE5-C74C+6DEB-CD4C + cheat + description:Have all secret power-ups on - P1 + code:EEEA-1FDC+EEEA-1F0C + cheat + description:Have all secret power-ups on - P2 + code:EEE1-C46C+EEE1-C4AC + cheat + description:Have all secret power-ups on - P3 + code:EEEF-3DDC+EEEF-3D0C + cheat + description:Have all secret power-ups on - P4 + code:EEE8-3F6C+EEE8-3FAC + cheat + description:Have Power Push - P1 + code:DFEA-1FDC + cheat + description:Have Powered Up 3 pointers - P1 + code:D4EA-1FDC + cheat + description:Have Powered Up 3 pointers - P2 + code:D4E1-C46C + cheat + description:Have Powered Up 3 pointers - P3 + code:D4EF-3DDC + cheat + description:Have Powered Up 3 pointers - P4 + code:D4E8-3F6C + cheat + description:Have Infinite Turbo - P1 + code:D0EA-1FDC + cheat + description:Have Infinite Turbo - P2 + code:D0E1-C46C + cheat + description:Have Infinite Turbo - P3 + code:D0EF-3DDC + cheat + description:Have Infinite Turbo - P4 + code:D0E8-3F6C + cheat + description:Always On Fire - P1 + code:D6EA-1FDC + cheat + description:Always On Fire - P2 + code:D6E1-C46C + cheat + description:Always On Fire - P3 + code:D6EF-3DDC + cheat + description:Always On Fire - P4 + code:D6E8-3F6C + cheat + description:Have Super Dunks - P1 + code:FDEA-1FDC + cheat + description:Have Super Dunks - P2 + code:FDE1-C46C + cheat + description:Have Super Dunks - P3 + code:FDEF-3DDC + cheat + description:Have Super Dunks - P4 + code:FDE8-3F6C + cheat + description:Have Max Power - P1 + code:4DEA-1FDC + cheat + description:Have Max Power - P2 + code:4DE1-C46C + cheat + description:Have Max Power - P3 + code:4DEF-3DDC + cheat + description:Have Max Power - P4 + code:4DE8-3F6C + cheat + description:Have Powered Up Goal Tending - P1 + code:0DEA-1FDC + cheat + description:Have Powered Up Goal Tending - P2 + code:0DE1-C46C + cheat + description:Have Powered Up Goal Tending - P3 + code:0DEF-3DDC + cheat + description:Have Powered Up Goal Tending - P4 + code:0DE8-3F6C + cheat + description:Have Quick Hands - P1 + code:6DEA-1FDC + cheat + description:Have Quick Hands - P2 + code:6DE1-C46C + cheat + description:Have Quick Hands - P3 + code:6DEF-3DDC + cheat + description:Have Quick Hands - P4 + code:6DE8-3F6C + cheat + description:Have Powered Up Offense - P1 + code:DFEA-1F0C + cheat + description:Have Powered Up Offense - P2 + code:DFE1-C4AC + cheat + description:Have Powered Up Offense - P3 + code:DFEF-3D0C + cheat + description:Have Powered Up Offense - P4 + code:DFE8-3FAC + cheat + description:Move very quickly - P1 + code:D4EA-1F0C + cheat + description:Move very quickly - P2 + code:D4E1-C4AC + cheat + description:Move very quickly - P3 + code:D4EF-3D0C + cheat + description:Move very quickly - P4 + code:D4E8-3FAC + cheat + description:Knock down both opponents by pushing one - P1 + code:D0EA-1F0C + cheat + description:Knock down both opponents by pushing two - P2 + code:D0E1-C4AC + cheat + description:Knock down both opponents by pushing three - P3 + code:D0EF-3D0C + cheat + description:Knock down both opponents by pushing four - P4 + code:D0E8-3FAC + cheat + description:Knock down opposite opponent - P1 + code:FDEA-1F0C + cheat + description:Knock down opposite opponent - P2 + code:FDE1-C4AC + cheat + description:Knock down opposite opponent - P3 + code:FDEF-3D0C + cheat + description:Knock down opposite opponent - P4 + code:FDE8-3FAC + cheat + description:Have High Shots - P1 + code:4DEA-1F0C + cheat + description:Have High Shots - P2 + code:4DE1-C4AC + cheat + description:Have High Shots - P3 + code:4DEF-3D0C + cheat + description:Have High Shots - P4 + code:4DE8-3FAC + cheat + description:Have Power Block - P2 + code:DFE1-C46C + cheat + description:Have Power Block - P3 + code:DFEF-3DDC + cheat + description:Have Power Block - P4 + code:DFE8-3F6C + cheat + description:Have Teleport Passes - P1 + code:D6EA-1F0C + cheat + description:Have Teleport Passes - P2 + code:D6E1-C4AC + cheat + description:Have Teleport Passes - P3 + code:D6EF-3D0C + cheat + description:Have Teleport Passes - P4 + code:D6E8-3FAC + cheat + description:Start with 1 point - P1 + code:33E0-4DAC + cheat + description:Start with 1 point - P2 + code:33E0-47AC + +cartridge sha256:3ef9d4b537ea83c8ba9ec8be7aba37ddac22a71c73d0aec46fe8e5a8f5b34a7c + title:NBA Jam (USA) (Rev 1) + cheat + description:Always On Fire - all players + code:D6E2-CFC8 + cheat + description:Always On Fire (alt) - all players + code:D6E9-CD18 + cheat + description:Have Infinite Turbo - all players + code:D6E3-C748 + cheat + description:Have Infinite Turbo (alt) - all players + code:D6E1-CF38 + cheat + description:Have Super Dunk ability - all players + code:D8E8-C718 + cheat + description:Have Super Dunk ability (alt) - all players + code:D8E7-C448 + cheat + description:Have Super Interception ability - all players + code:D8E6-C7C8 + cheat + description:Have Super Interception ability (alt) - all players + code:D8ED-C418 + cheat + description:Juice mode + code:D6ED-3DC8 + cheat + description:Juice mode (alt) + code:D6E5-C718 + cheat + description:Visitor's baskets worth 1 + code:BBCC-0F6F + cheat + description:Visitor's baskets worth 2 + code:34CC-0F6F + cheat + description:Visitor's baskets worth 3 + code:30CC-0F6F + cheat + description:Visitor's baskets worth 4 + code:39CC-0F6F + cheat + description:Visitor's baskets worth 5 + code:35CC-0F6F + cheat + description:Visitor's baskets worth 6 + code:36CC-0F6F + cheat + description:Visitor's baskets worth 7 + code:3CCC-0F6F + cheat + description:Visitor's baskets worth 8 + code:3ACC-0F6F + cheat + description:Home's baskets worth 1 + code:BBC6-A7AF + cheat + description:Home's baskets worth 2 + code:34C6-A7AF + cheat + description:Home's baskets worth 3 + code:30C6-A7AF + cheat + description:Home's baskets worth 4 + code:39C6-A7AF + cheat + description:Home's baskets worth 5 + code:35C6-A7AF + cheat + description:Home's baskets worth 6 + code:36C6-A7AF + cheat + description:Home's baskets worth 7 + code:3CC6-A7AF + cheat + description:Home's baskets worth 8 + code:3AC6-A7AF + cheat + description:Shot success percentages displayed for non-dunk shots + code:D6EC-CF38 + cheat + description:Shot success percentages displayed for non-dunk shots (alt) + code:D6E4-CDC8 + cheat + description:Need 2 baskets to be On Fire + code:D4BD-3038+D4BA-C948 + cheat + description:Need 4 baskets to be On Fire + code:D0BD-3038 + cheat + description:Need 5 baskets to be On Fire + code:D9BD-3038 + cheat + description:Need 6 baskets to be On Fire + code:D1BD-3038 + cheat + description:Need 7 baskets to be On Fire + code:D5BD-3038 + cheat + description:Need 8 baskets to be On Fire + code:D6BD-3038 + cheat + description:Need 9 baskets to be On Fire + code:DBBD-3038 + cheat + description:Need 10 baskets to be On Fire + code:DCBD-3038 + cheat + description:Need 2 baskets to stay On Fire until an opponent goes On Fire + code:D4BD-3038 + cheat + description:Turbo bar never goes up (until next quarter) + code:DDE6-3B2A + cheat + description:Turbo bar never goes up (until next quarter) (alt) + code:DDE1-3C2A + cheat + description:Turbo bar restores very slowly + code:D3E6-3B2A + cheat + description:Turbo bar restores very slowly (alt) + code:D3E1-3C2A + cheat + description:Turbo bar restores much slower + code:F9E6-3B2A + cheat + description:Turbo bar restores much slower (alt) + code:F9E1-3C2A + cheat + description:Turbo bar restores slower + code:F2E6-3B2A + cheat + description:Turbo bar restores slower (alt) + code:F2E1-3C2A + cheat + description:Turbo bar restores faster + code:0DE6-3B2A + cheat + description:Turbo bar restores faster (alt) + code:0DE1-3C2A + cheat + description:Turbo bar restores much faster + code:9DE6-3B2A + cheat + description:Turbo bar restores much faster (alt) + code:9DE1-3C2A + cheat + description:Turbo bar restores extremely fast + code:6FE6-3B2A + cheat + description:Turbo bar restores extremely fast (alt) + code:6FE1-3C2A + cheat + description:Turbo drains very slowly + code:D0E5-3CFA + cheat + description:Turbo drains very slowly (alt) + code:D0E9-38FA + cheat + description:Turbo drains slower + code:D6E5-3CFA + cheat + description:Turbo drains slower (alt) + code:D6E9-38FA + cheat + description:Turbo drains slightly slower + code:FDE5-3CFA + cheat + description:Turbo drains slightly slower (alt) + code:FDE9-38FA + cheat + description:Turbo drains slightly faster + code:44E5-3CFA + cheat + description:Turbo drains slightly faster (alt) + code:44E9-38FA + cheat + description:Turbo drains faster + code:42E5-3CFA + cheat + description:Turbo drains faster (alt) + code:42E9-38FA + cheat + description:Turbo drains very fast + code:76E5-3CFA + cheat + description:Turbo drains very fast (alt) + code:76E9-38FA + cheat + description:Always On Fire - P1 + code:7E0A96:01 + cheat + description:Always On Fire - P2 + code:7E0A96:03 + +cartridge sha256:0f18c496426bb97fe5e8b91ad5299f0b1c3898ac17047b745c86b167c212ab7a + title:NBA Jam (USA) + cheat + description:Always On Fire - all players + code:D6E2-CFC8 + cheat + description:Always On Fire (alt) - all players + code:D6E9-CD18 + cheat + description:Have Infinite Turbo - all players + code:D6E3-C748 + cheat + description:Have Infinite Turbo (alt) - all players + code:D6E1-CF38 + cheat + description:Have Super Dunk ability - all players + code:D8E8-C718 + cheat + description:Have Super Dunk ability (alt) - all players + code:D8E7-C448 + cheat + description:Have Super Interception ability - all players + code:D8E6-C7C8 + cheat + description:Have Super Interception ability (alt) - all players + code:D8ED-C418 + cheat + description:Juice mode + code:D6ED-3DC8 + cheat + description:Juice mode (alt) + code:D6E5-C718 + cheat + description:Visitor's baskets worth 1 + code:BBCC-0F6F + cheat + description:Visitor's baskets worth 2 + code:34CC-0F6F + cheat + description:Visitor's baskets worth 3 + code:30CC-0F6F + cheat + description:Visitor's baskets worth 4 + code:39CC-0F6F + cheat + description:Visitor's baskets worth 5 + code:35CC-0F6F + cheat + description:Visitor's baskets worth 6 + code:36CC-0F6F + cheat + description:Visitor's baskets worth 7 + code:3CCC-0F6F + cheat + description:Visitor's baskets worth 8 + code:3ACC-0F6F + cheat + description:Home's baskets worth 1 + code:BBC6-A7AF + cheat + description:Home's baskets worth 2 + code:34C6-A7AF + cheat + description:Home's baskets worth 3 + code:30C6-A7AF + cheat + description:Home's baskets worth 4 + code:39C6-A7AF + cheat + description:Home's baskets worth 5 + code:35C6-A7AF + cheat + description:Home's baskets worth 6 + code:36C6-A7AF + cheat + description:Home's baskets worth 7 + code:3CC6-A7AF + cheat + description:Home's baskets worth 8 + code:3AC6-A7AF + cheat + description:Shot success percentages displayed for non-dunk shots + code:D6EC-CF38 + cheat + description:Shot success percentages displayed for non-dunk shots (alt) + code:D6E4-CDC8 + cheat + description:Need 2 baskets to be On Fire + code:D4BD-3038+D4BA-C948 + cheat + description:Need 4 baskets to be On Fire + code:D0BD-3038 + cheat + description:Need 5 baskets to be On Fire + code:D9BD-3038 + cheat + description:Need 6 baskets to be On Fire + code:D1BD-3038 + cheat + description:Need 7 baskets to be On Fire + code:D5BD-3038 + cheat + description:Need 8 baskets to be On Fire + code:D6BD-3038 + cheat + description:Need 9 baskets to be On Fire + code:DBBD-3038 + cheat + description:Need 10 baskets to be On Fire + code:DCBD-3038 + cheat + description:Need 2 baskets to stay On Fire until an opponent goes On Fire + code:D4BD-3038 + cheat + description:Turbo bar never goes up (until next quarter) + code:DDE6-3B2A + cheat + description:Turbo bar never goes up (until next quarter) (alt) + code:DDE1-3C2A + cheat + description:Turbo bar restores very slowly + code:D3E6-3B2A + cheat + description:Turbo bar restores very slowly (alt) + code:D3E1-3C2A + cheat + description:Turbo bar restores much slower + code:F9E6-3B2A + cheat + description:Turbo bar restores much slower (alt) + code:F9E1-3C2A + cheat + description:Turbo bar restores slower + code:F2E6-3B2A + cheat + description:Turbo bar restores slower (alt) + code:F2E1-3C2A + cheat + description:Turbo bar restores faster + code:0DE6-3B2A + cheat + description:Turbo bar restores faster (alt) + code:0DE1-3C2A + cheat + description:Turbo bar restores much faster + code:9DE6-3B2A + cheat + description:Turbo bar restores much faster (alt) + code:9DE1-3C2A + cheat + description:Turbo bar restores extremely fast + code:6FE6-3B2A + cheat + description:Turbo bar restores extremely fast (alt) + code:6FE1-3C2A + cheat + description:Turbo drains very slowly + code:D0E5-3CFA + cheat + description:Turbo drains very slowly (alt) + code:D0E9-38FA + cheat + description:Turbo drains slower + code:D6E5-3CFA + cheat + description:Turbo drains slower (alt) + code:D6E9-38FA + cheat + description:Turbo drains slightly slower + code:FDE5-3CFA + cheat + description:Turbo drains slightly slower (alt) + code:FDE9-38FA + cheat + description:Turbo drains slightly faster + code:44E5-3CFA + cheat + description:Turbo drains slightly faster (alt) + code:44E9-38FA + cheat + description:Turbo drains faster + code:42E5-3CFA + cheat + description:Turbo drains faster (alt) + code:42E9-38FA + cheat + description:Turbo drains very fast + code:76E5-3CFA + cheat + description:Turbo drains very fast (alt) + code:76E9-38FA + cheat + description:Always On Fire - P1 + code:7E0A96:01 + cheat + description:Always On Fire - P2 + code:7E0A96:03 + +cartridge sha256:6a7324734004d99206439430243b51a05fa8c25ffa314dafc7f127235d1a730f + title:NBA Showdown (USA) + cheat + description:Infinite time + code:C224-4DA4 + cheat + description:Infinite time-outs + code:C239-1F6D + cheat + description:No personal fouls - both teams + code:C23B-44A8 + cheat + description:Infinite shot clock - computer + code:C220-4FDF + cheat + description:12-sec. shot clock when ball is in-bounded - P1 + code:DAE3-14AA+DAB7-37DA+DA3F-140F + cheat + description:12-sec. shot clock when ball is in-bounded - computer + code:DAE3-14AA+DA6E-47D8+DA84-CDDB + cheat + description:1-min. quarters + code:DFED-342C + cheat + description:3 time-outs + code:D7E1-1D6A + +cartridge sha256:8ef5d5c50ffeca1e62e88e4fe2909eaf191e28fbb5a9faf98b7b10bea72c9ed9 + title:NCAA Basketball (USA) (Rev 1) + cheat + description:Infinite time to shoot + code:C2B5-DDA9 + cheat + description:Infinite timeouts - P1 + code:C224-6FDF + cheat + description:Infinite timeouts - P2 + code:C224-676F + cheat + description:Shot timer starts at 10 sec. instead of 45 + code:FDBB-DDD9 + cheat + description:Shot timer starts at 20 sec. + code:4DBB-DDD9 + cheat + description:Shot timer starts at 30 sec. + code:7DBB-DDD9 + cheat + description:Shot timer starts at 60 sec. + code:1DBB-DDD9 + cheat + description:Shot timer starts at 90 sec. + code:BDBB-DDD9 + cheat + description:3-point shots worth 0 - both players + code:DD34-A767 + cheat + description:3-point shots worth 1 point + code:DF34-A767 + cheat + description:3-point shots worth 2 points + code:D434-A767 + cheat + description:3-point shots worth 4 points + code:D034-A767 + cheat + description:3-point shots worth 5 points + code:D934-A767 + cheat + description:3-point shots worth 6 points + code:D134-A767 + cheat + description:3-point shots worth 7 points + code:D534-A767 + cheat + description:3-point shots worth 8 points + code:D634-A767 + cheat + description:3-point shots worth 9 points + code:DB34-A767 + cheat + description:P1 shots worth 1 extra point (2-pt. shots worth 3, 3-pt. shots worth 4) + code:76BA-A404+76B9-6FA7 + cheat + description:P2 shots worth 1 extra point (2-pt. shots worth 3, 3-pt. shots worth 4) + code:76B0-64A7+76B8-A704 + cheat + description:P1 free throws worth 2 instead of 1 + code:76BD-0D07 + cheat + description:P2 free throws worth 2 + code:76BE-DF07 + cheat + description:No 5-second violations + code:C265-D4D7 + +cartridge sha256:d44f487d84f5bb761955b7b70a5464b2f094e199875f595f312c88e04ac647ff + title:NHL Stanley Cup (USA) (En,Fr) + cheat + description:Visitor starts with 1 point (exhibition mode) + code:DF67-CDA4+D667-CFA4+E667-CF64 + cheat + description:Home starts with 1 point (exhibition mode) + code:DF67-CDA4+D667-CFA4+EC67-CF64 + cheat + description:Visitor starts with 3 points (exhibition mode) + code:D767-CDA4+D667-CFA4+E667-CF64 + cheat + description:Home starts with 3 points (exhibition mode) + code:D767-CDA4+D667-CFA4+EC67-CF64 + cheat + description:Visitor starts with 5 points (exhibition mode) + code:D967-CDA4+D667-CFA4+E667-CF64 + cheat + description:Home starts with 5 points (exhibition mode) + code:D967-CDA4+D667-CFA4+EC67-CF64 + cheat + description:Visitor starts with 7 points (exhibition mode) + code:D567-CDA4+D667-CFA4+E667-CF64 + cheat + description:Home starts with 7 points (exhibition mode) + code:D567-CDA4+D667-CFA4+EC67-CF64 + cheat + description:Visitor starts with 9 points (exhibition mode) + code:DB67-CDA4+D667-CFA4+E667-CF64 + cheat + description:Home starts with 9 points (exhibition mode) + code:DB67-CDA4+D667-CFA4+EC67-CF64 + cheat + description:Visitor scores 1 point for goals, Home scores 3 + code:1BA1-4D01 + cheat + description:Periods are 1 min (choose 5 minutes from Options) + code:DFE0-CD0F + cheat + description:Periods are 3 min (choose 5 minutes from Options) + code:D7E0-CD0F + cheat + description:Periods are 7 min (choose 5 minutes from Options) + code:D5E0-CD0F + cheat + description:Periods are 9 min (choose 5 minutes from Options) + code:DBE0-CD0F + cheat + description:Periods are 15 min (choose 10 minutes from Options) + code:94ED-C46F + cheat + description:Periods are 30 min (choose 10 minutes from Options) + code:D7E0-C76F + cheat + description:Penalty for charging is 1 minute instead of 2 + code:7A2B-3F00 + cheat + description:Penalty for holding is 1 minute instead of 2 + code:7A2B-3760 + cheat + description:Penalty for tripping is 1 minute instead of 2 + code:7A2C-3FA0 + cheat + description:Penalty for high sticking is 1 minute instead of 2 + code:7A28-3DD0 + cheat + description:Penalty for elbowing is 1 minute instead of 2 + code:7A28-3400 + cheat + description:Penalty for hooking is 1 minute instead of 2 + code:7A2A-3D60 + cheat + description:Penalty for roughing is 1 minute instead of 2 + code:7A2A-34A0 + cheat + description:Penalty for slashing is 1 minute instead of 4 + code:7A22-3FD0 + cheat + description:Penalty for spearing is 1 minute instead of 2 + code:7A22-3700 + cheat + description:Penalty for charging is 30 seconds + code:F32B-3F00 + cheat + description:Penalty for holding is 30 seconds + code:F32B-3760 + cheat + description:Penalty for tripping is 30 seconds + code:F32C-3FA0 + cheat + description:Penalty for high sticking is 30 seconds + code:F328-3DD0 + cheat + description:Penalty for elbowing is 30 seconds + code:F328-3400 + cheat + description:Penalty for hooking is 30 seconds + code:F32A-3D60 + cheat + description:Penalty for roughing is 30 seconds + code:F32A-34A0 + cheat + description:Penalty for slashing is 30 seconds + code:F322-3FD0 + cheat + description:Penalty for spearing is 30 seconds + code:F322-3700 + cheat + description:Penalty for charging is 3 minutes + code:802B-3F00 + cheat + description:Penalty for holding is 3 minutes + code:802B-3760 + cheat + description:Penalty for tripping is 3 minutes + code:802C-3FA0 + cheat + description:Penalty for high sticking is 3 minutes + code:8028-3DD0 + cheat + description:Penalty for elbowing is 3 minutes + code:8028-3400 + cheat + description:Penalty for hooking is 3 minutes + code:802A-3D60 + cheat + description:Penalty for roughing is 3 minutes + code:802A-34A0 + cheat + description:Penalty for slashing is 3 minutes + code:8022-3FD0 + cheat + description:Penalty for spearing is 3 minutes + code:8022-3700 + +cartridge sha256:55f3432a130085c112d65aa6443c41eb7a8aeec59aad2c2b4b2ac536b604b449 + title:NHLPA Hockey '93 (USA) + cheat + description:Period clock runs faster + code:F160-4776 + cheat + description:Period clock runs slower + code:D060-4776 + cheat + description:Period clock runs much faster + code:0D60-4776 + cheat + description:Period clock runs much slower + code:DF60-4776 + cheat + description:Period clock is frozen (no time limit) + code:C269-4D86 + cheat + description:Each period lasts 1 minute instead of 10 minutes + code:7AE8-4D98+DDE8-4DB8 + cheat + description:Each period lasts 2 minutes + code:56E8-4D98+DDE8-4DB8 + cheat + description:Each period lasts 3 minutes + code:80E8-4D98+DDE8-4DB8 + cheat + description:Each period lasts 4 minutes + code:EDE8-4D98+DDE8-4DB8 + cheat + description:Each period lasts 15 minutes + code:60E8-4D98+D7E8-4DB8 + cheat + description:Each period lasts 30 minutes + code:D6E8-4D98+D5E8-4DB8 + cheat + description:Each period lasts 40 minutes + code:1DE8-4D98+DBE8-4DB8 + cheat + description:Each period lasts 60 minutes + code:FDE8-4D98+D3E8-4DB8 + cheat + description:All penalties last 1 minute + code:DF31-3F64+CB31-3F04 + cheat + description:All penalties last 2 minutes + code:D431-3F64+CB31-3F04 + cheat + description:All penalties last 3 minutes + code:D731-3F64+CB31-3F04 + cheat + description:All penalties last 4 minutes + code:D031-3F64+CB31-3F04 + cheat + description:All penalties last 5 minutes + code:D931-3F64+CB31-3F04 + cheat + description:All penalties last 7 minutes + code:D531-3F64+CB31-3F04 + cheat + description:All penalties last 9 minutes + code:DB31-3F64+CB31-3F04 + +cartridge sha256:d7ad6f67860da78fe25d9e79dd13af7ac7efaa0c8e0103898a4849ab4af9e438 + title:Nickelodeon GUTS (USA) + cheat + description:Gain lots of points in Slam Dunk / Attack levels + code:7E126D:FF + +cartridge sha256:ce9c819d6496e58901b39d9b04558a89e09ccc3aac33690b8d02bb0406682a57 + title:Nigel Mansell's World Championship Racing (USA) + cheat + description:Almost no tire wear (graphic distortion in the pits) + code:C96B-1705+C9B1-4D61 + cheat + description:Only 1 lap required on all tracks + code:E481-3467 + cheat + description:Only 3 laps required in South Africa + code:D461-4FBA + cheat + description:Only 3 laps required in Mexico + code:D461-44FA + cheat + description:Only 3 laps required in Brazil + code:D461-44BA + cheat + description:Only 3 laps required in Spain + code:D461-47FA + cheat + description:Only 3 laps required in San Marino + code:D461-47BA + cheat + description:Only 3 laps required in Monaco + code:D465-4DFA + cheat + description:Only 3 laps required in Canada + code:D465-4DBA + cheat + description:Only 3 laps required in France + code:D465-4FFA + cheat + description:Only 3 laps required in Britain + code:D465-4FBA + cheat + description:Only 3 laps required in Germany + code:D465-44FA + cheat + description:Only 3 laps required in Hungary + code:D465-44BA + cheat + description:Only 3 laps required in Belgium + code:D465-47FA + cheat + description:Only 3 laps required in Italy + code:D465-47BA + cheat + description:Only 3 laps required in Portugal + code:D466-4DFA + cheat + description:Only 3 laps required in Japan + code:D466-4DBA + cheat + description:Only 3 laps required in Australia + code:D466-4FFA + cheat + description:Full season ends after South Africa + code:DF3E-015A + cheat + description:Full season ends after Mexico + code:D43E-015A + cheat + description:Full season ends after Brazil + code:D73E-015A + cheat + description:Full season ends after Spain + code:D03E-015A + cheat + description:Full season ends after San Marino + code:D93E-015A + cheat + description:Full season ends after Monaco + code:D13E-015A + cheat + description:Full season ends after Canada + code:D53E-015A + cheat + description:Full season ends after France + code:D63E-015A + cheat + description:Full season ends after Britain + code:DB3E-015A + cheat + description:Full season ends after Germany + code:DC3E-015A + cheat + description:Full season ends after Hungary + code:D83E-015A + cheat + description:Full season ends after Belgium + code:DA3E-015A + cheat + description:Full season ends after Italy + code:D23E-015A + cheat + description:Full season ends after Portugal + code:D33E-015A + cheat + description:Full season ends after Japan + code:DE3E-015A + cheat + description:Start in Mexico in the Full Season + code:DF62-0953 + cheat + description:Start in Brazil + code:D462-0953 + cheat + description:Start in Spain + code:D762-0953 + cheat + description:Start in San Marino + code:D062-0953 + cheat + description:Start in Monaco + code:D962-0953 + cheat + description:Start in Canada + code:D162-0953 + cheat + description:Start in France + code:D562-0953 + cheat + description:Start in Britain + code:D662-0953 + cheat + description:Start in Germany + code:DB62-0953 + cheat + description:Start in Hungary + code:DC62-0953 + cheat + description:Start in Belgium + code:D862-0953 + cheat + description:Start in Italy + code:DA62-0953 + cheat + description:Start in Portugal + code:D262-0953 + cheat + description:Start in Japan + code:D362-0953 + cheat + description:Start in Australia + code:DE62-0953 + cheat + description:Start on extra course (stats are for South Africa but the course is different) + code:FD62-0953 + +cartridge sha256:fccc96af24a2463b1c53253e1c5c8ef63641355fae53c0fb410427f29743262b + title:Ninja Gaiden Trilogy (USA) + cheat + description:(NG) Invincibility + code:6DB5-3797 + cheat + description:(NG) Infinite health + code:C9C3-3F2D + cheat + description:(NG) Infinite lives + code:C9CF-CFBF + cheat + description:(NG) Infinite time + code:DD81-1F97 + cheat + description:(NG) Start with very little time + code:B1C8-3DF8 + cheat + description:(NG) Start with lots of time + code:EEC8-3DF8 + cheat + description:(NG) Start with very little health (after first life) + code:DFCE-142F + cheat + description:(NG) Start with about half health (after first life) + code:DFCE-142F + cheat + description:(NG) Start with 1 life + code:DDC5-4DF4 + cheat + description:(NG) Start with 5 lives + code:D7C5-4DF4 + cheat + description:(NG) Start with 9 lives + code:D6C5-4DF4 + cheat + description:(NGII) Invincibility + code:1DB4-CD4D + cheat + description:(NGII) Infinite health + code:C9BB-441F + cheat + description:(NGII) Infinite lives + code:C961-3D37 + cheat + description:(NGII) Infinite time + code:C96F-1FC7 + cheat + description:(NGII) Start with very little health + code:DFB3-144F + cheat + description:(NGII) Start with about half health + code:D6B3-144F + cheat + description:(NGII) Start every life with two Shadow Ninjas + code:DEB9-14C4 + cheat + description:(NGII) Throwing stars don't use Ninja Power (ignore counter) + code:DFC4-1F47 + cheat + description:(NGII) Start with 1 life + code:DDB3-C4CF + cheat + description:(NGIII) Invincibility + code:DDAB-3FE7 + cheat + description:(NGIII) Infinite health + code:C92A-CFED + cheat + description:(NGIII) Infinite lives + code:CB69-CD57 + cheat + description:(NGIII) Infinite time + code:C927-17EF + cheat + description:(NGIII) Almost infinite Ninja Power + code:C9A7-C757 + cheat + description:(NGIII) Start with 99 Ninja Power (ignore the counter) + code:176C-CDE7 + cheat + description:(NGIII) Start with 1 life + code:DD6B-CF87 + cheat + description:(NGIII) Start with 5 lives + code:D76B-CF87 + cheat + description:(NGIII) Start with 9 lives + code:D66B-CF87 + cheat + description:(NGIII) Start with very little health + code:DF68-CD77 + cheat + description:(NGIII) Start with about half health + code:D668-CD77 + cheat + description:(NG) Invincibility after first hit + code:7E0093:01 + cheat + description:(NG) Infinite Ninja Power + code:7E0064:63 + cheat + description:(NG) Auto kill enemies that are close by + code:849F92:80+849F9F:80 + cheat + description:(NGII) Invincibility (alt) + code:7E0068:25 + cheat + description:(NGII) Infinite Ninja Power + code:7E00AE:63 + cheat + description:(NGII) Always have Fireball + code:7E007D:02 + cheat + description:(NGIII) Infinite lives (alt) + code:7E00C4:03 + cheat + description:(NGIII) Infinite Ninja Power + code:7E00CD:63 + +cartridge sha256:3c109e50b91ec6df3bb8509778ae544c99433fb40dda9b801178dfe513053618 + title:Ninjawarriors, The (USA) + cheat + description:Invincibility + code:EDB0-D768+ED8D-AD0B+2DB1-DDD8+2DB1-DF08+2D8D-A70B + cheat + description:Infinite health + code:C2B0-DD6C + cheat + description:Infinite time + code:62C4-6DD7 + cheat + description:Infinite specials once you obtain one + code:CECB-A467 + cheat + description:One hit kills + code:CB68-D7AE+DD6A-DDDE+DD6A-DD0E+CBCE-ADD6+DDCE-AD06+DDCE-AD66 + +cartridge sha256:f099937ac4c8afb38c517c5d85475224985fb8f345dacb44994a617ea05bf4e5 + title:No Escape (USA) + cheat + description:Infinite health + code:852A-CF67 + cheat + description:Infinite time + code:CBB4-C75F + cheat + description:Infinite lives + code:842F-44A7 + +cartridge sha256:7f3d0ebac6ecfb99cfd1d5b13210e989df9e8b2f2319a63c42faef8ad115a964 + title:Nolan Ryan's Baseball (USA) + cheat + description:1 strike and batter is out + code:A3BF-6DD1 + cheat + description:Batter never strikes out + code:C2BF-6DD1 + cheat + description:1 ball and batter walks + code:A3BE-0D61 + cheat + description:Batter never walks + code:C2BE-0D61 + cheat + description:Each run worth 2 - P1 + code:76AC-0D65 + cheat + description:Each run worth 2 - P2 + code:76A8-04D5 + cheat + description:Short game (play only odd-numbered innings) + code:766D-67A5 + cheat + description:Increasing a player's power setting does not decrease the power number excess (use to maximize stats for a player) + code:DDC8-D706 + cheat + description:Maximum power for a player is 32 instead of 25 + code:4DBF-A7A8 + cheat + description:Maximum power for a player is 40 instead of 25 + code:46BF-A7A8 + cheat + description:Maximum power for a player is 48 + code:7DBF-A7A8 + +cartridge sha256:9712829b38f23229d4e3d65da78237659c790235f425c6b12487e4d9e9a37ae9 + title:Nosferatu (USA) + cheat + description:Almost infinite health + code:C9BA-1F04 + cheat + description:Infinite time + code:C127-4D67 + cheat + description:Don't lose crystals when you get hit + code:C265-3DBD + cheat + description:Start with very little health + code:DFB2-34D7 + cheat + description:Start with less health + code:D7B2-34D7 + cheat + description:Start with more health + code:DBB2-34D7 + cheat + description:Start with a lot more health + code:DEB2-34D7 + cheat + description:Start with more time + code:CBCE-CDAD+44CE-CFDD+DDCE-CF0D + cheat + description:Start on stage 1-2 + code:D1B3-3DA7 + cheat + description:Start on stage 1-3 + code:DBB3-3DA7 + cheat + description:Start on stage 2 + code:DCB3-3DA7 + cheat + description:Start on stage 2-2 + code:FDB3-3DA7 + cheat + description:Start on stage 2-3 + code:FFB3-3DA7 + cheat + description:Start on stage 2-4 + code:F5B3-3DA7 + cheat + description:Start on stage 3 + code:F6B3-3DA7 + cheat + description:Start on stage 3-2 + code:4DB3-3DA7 + cheat + description:Start on stage 3-3 + code:40B3-3DA7 + cheat + description:Start on stage 4 + code:45B3-3DA7 + cheat + description:Start on stage 4-2 + code:42B3-3DA7 + cheat + description:Start on stage 4-3 + code:43B3-3DA7 + cheat + description:Start on stage 4-4 + code:70B3-3DA7 + cheat + description:Start on stage 5 + code:79B3-3DA7 + cheat + description:Start on stage 5-2 + code:78B3-3DA7 + cheat + description:Start on stage 5-3 + code:7AB3-3DA7 + cheat + description:Start on stage 5-4 + code:09B3-3DA7 + cheat + description:Start on stage 6 + code:01B3-3DA7 + cheat + description:Start on stage 6-2 + code:03B3-3DA7 + cheat + description:Start on the final stage + code:90B3-3DA7 + cheat + description:Start on the final stage with more crystals + code:90B3-3DA7+62B3-3FA7 + cheat + description:View the ending + code:91B3-3DA7 + +cartridge sha256:31bc862ab0a8eabf23b5124e13940cb3501e7ecdd3f15e34142248ceb4aa139a + title:Obitus (USA) + cheat + description:Infinite health + code:7E1113:20 + cheat + description:Infinite Stamina + code:7E1117:20 + cheat + description:Infinite Daggers (keep off until you obtain one) + code:7F132E:02 + cheat + description:Infinite Silver Keys (keep off until you obtain one) + code:7F0ED8:02 + cheat + description:Infinite Gold Coins (keep off until you obtain one) + code:7F0E8E:63 + +cartridge sha256:b766c26498d0afd63f44aefdef42642d2483b54f18d2b81a4f1d67a57f641044 + title:Ogre Battle - The March of the Black Queen (USA) + cheat + description:Level up after every battle (even if you run away) + code:DD2F-AFF4 + cheat + description:View 'Edit Units' screen to give everyone 2778 max HP (2000 of it won't be visible, and you won't get your HP restored. It will go down to 999 max HP if it tries to update the amount) + code:CBE7-A70C+B2E0-AD6C+2CE0-ADAC+DCE0-AFDC + cheat + description:View someone's stats from 'Edit Units' screen to give them max Luck + code:CB67-ADFB+EE67-AD9B+3C67-ADBB+BE67-AD2B + cheat + description:View someone's stats from 'Edit Units' screen to give them max Cha + code:CB6F-A7FB+196F-A79B+3C6F-A7BB+BE6F-A72B + cheat + description:Every hidden thing is visible when you first enter an area + code:CB6A-AD20+CB6A-AF90+EE6A-AFB0 + cheat + description:Leader's group moves 'Sky High' + code:DDE6-1D68 + cheat + description:Lans' group moves 'Sky High' + code:DDE7-1F68 + cheat + description:Judgement tarot card is stronger + code:EE20-070E + +cartridge sha256:e153195de7b59dd5b9854952cccca6bb93164e5fdff8292124bee6bbe5dbf16f + title:On the Ball (USA) + cheat + description:Infinite credits + code:C2AE-DF65 + cheat + description:Faster timer + code:D4BB-D404 + cheat + description:Stop timer - not lap timer (can still lose time by hitting hazards) + code:DDBB-D404 + cheat + description:Minus blocks and bricks worth 0 (don't combine with other minus codes) + code:C2BA-D7D4 + cheat + description:Minus 2 second block worth 0 + code:DDB7-0DA5 + cheat + description:Minus 2 second block worth minus 1 + code:FDB7-0DA5 + cheat + description:Minus 2 second block worth minus 3 + code:7DB7-0DA5 + cheat + description:Minus 2 second block worth minus 4 + code:0DB7-0DA5 + cheat + description:Minus 2 second block worth minus 5 + code:9DB7-0DA5 + cheat + description:Minus 2 second block worth minus 6 + code:1DB7-0DA5 + cheat + description:Minus 2 second block worth minus 7 + code:5DB7-0DA5 + cheat + description:Minus 2 second block worth minus 8 + code:6DB7-0DA5 + cheat + description:Minus 2 second block worth minus 9 + code:BDB7-0DA5 + cheat + description:Minus 5 second block worth 0 + code:DDB0-0F65 + cheat + description:Minus 5 second block worth minus 1 + code:FDB0-0F65 + cheat + description:Minus 5 second block worth minus 2 + code:4DB0-0F65 + cheat + description:Minus 5 second block worth minus 3 + code:7DB0-0F65 + cheat + description:Minus 5 second block worth minus 4 + code:0DB0-0F65 + cheat + description:Minus 5 second block worth minus 6 + code:1DB0-0F65 + cheat + description:Minus 5 second block worth minus 7 + code:5DB0-0F65 + cheat + description:Minus 5 second block worth minus 8 + code:6DB0-0F65 + cheat + description:Minus 5 second block worth minus 9 + code:BDB0-0F65 + cheat + description:Minus 3 second brick worth 0 + code:DDB9-0405 + cheat + description:Minus 3 second brick worth minus 1 + code:FDB9-0405 + cheat + description:Minus 3 second brick worth minus 2 + code:4DB9-0405 + cheat + description:Minus 3 second brick worth minus 4 + code:0DB9-0405 + cheat + description:Minus 3 second brick worth minus 5 + code:9DB9-0405 + cheat + description:Minus 3 second brick worth minus 6 + code:1DB9-0405 + cheat + description:Minus 3 second brick worth minus 7 + code:5DB9-0405 + cheat + description:Minus 3 second brick worth minus 8 + code:6DB9-0405 + cheat + description:Minus 3 second brick worth minus 9 + code:BDB9-0405 + cheat + description:Plus bricks worth 0 (don't combine with other plus bricks codes) + code:C2B8-DFA4 + cheat + description:Plus 3 bricks worth 0 + code:DDBB-0DA5 + cheat + description:Plus 3 bricks worth plus 1 + code:FDBB-0DA5 + cheat + description:Plus 3 bricks worth plus 2 + code:4DBB-0DA5 + cheat + description:Plus 3 bricks worth plus 4 + code:0DBB-0DA5 + cheat + description:Plus 3 bricks worth plus 5 + code:9DBB-0DA5 + cheat + description:Plus 3 bricks worth plus 6 + code:1DBB-0DA5 + cheat + description:Plus 3 bricks worth plus 7 + code:5DBB-0DA5 + cheat + description:Plus 3 bricks worth plus 8 + code:6DBB-0DA5 + cheat + description:Plus 3 bricks worth plus 9 + code:BDBB-0DA5 + cheat + description:Plus 5 bricks worth 0 + code:DDBC-0F65 + cheat + description:Plus 5 bricks worth plus 1 + code:FDBC-0F65 + cheat + description:Plus 5 bricks worth plus 2 + code:4DBC-0F65 + cheat + description:Plus 5 bricks worth plus 3 + code:7DBC-0F65 + cheat + description:Plus 5 bricks worth plus 4 + code:0DBC-0F65 + cheat + description:Plus 5 bricks worth plus 6 + code:1DBC-0F65 + cheat + description:Plus 5 bricks worth plus 7 + code:5DBC-0F65 + cheat + description:Plus 5 bricks worth plus 8 + code:6DBC-0F65 + cheat + description:Plus 5 bricks worth plus 9 + code:BDBC-0F65 + cheat + description:Start with 2 credits + code:DF66-DDA0 + cheat + description:Start with 6 credits + code:D966-DDA0 + cheat + description:Start with 8 credits + code:D566-DDA0 + cheat + description:Start with 10 credits + code:DB66-DDA0 + +cartridge sha256:190742792a950a112f893cba0e083eb787cf24293f698967defff929635ba0e7 + title:Operation Logic Bomb (USA) + cheat + description:Infinite health + code:C2B5-4DD0 + cheat + description:Take minimal damage + code:33C6-C704 + cheat + description:Faster left-to-right movement + code:E2B2-1F00+D4BA-1700 + cheat + description:Faster up-and-down movement + code:E2BD-CFA0+D4B3-1FA0 + cheat + description:Reflecting laser fire travels longer + code:1DB2-44D9 + cheat + description:Reflecting laser fire travels a lot longer + code:EEB2-44D9 + cheat + description:Start with 1 continue + code:DFB4-1FD4 + cheat + description:Start with 6 continues + code:D1B4-1FD4 + cheat + description:Start with 9 continues + code:DBB4-1FD4 + cheat + description:Start with tracking missiles + code:D7BD-1D64+4DBE-4DD4+40BD-1FD4 + cheat + description:Start with reflecting laser + code:D0BD-1D64+4DBE-4DD4+40BD-1FD4 + cheat + description:Start with flame thrower + code:D9BD-1D64+4DBE-4DD4+40BD-1FD4 + cheat + description:Start with hologram weapon + code:DFBF-1FD4+BABF-14D4+BABF-14A4 + cheat + description:Start with directional mines + code:D4BF-1FD4+BABF-14D4+BABF-14A4 + cheat + description:Infinite health (alt) + code:819070:AD + cheat + description:Infinite weapons + code:03ED4E:01 + cheat + description:Start with Tracking Missiles (alt) + code:8098F0:20+809902:03+809904:24 + cheat + description:Start with Reflecting Laser (alt) + code:8098F0:20+809902:04+809904:24 + cheat + description:Start with Flame Thrower (alt) + code:8098F0:20+809902:05+809904:24 + cheat + description:Start with Hologram weapon (alt) + code:809914:01+809918:9C+80991B:9C + cheat + description:Start with Directional Mines (alt) + code:809914:02+809918:9C+80991B:9C + cheat + description:Faster left-to-right movement (alt) + code:8191CD:02+8191D5:FD + cheat + description:Faster up-and-down movement (alt) + code:8191E7:02+819207:FD + cheat + description:Reflecting laser fire travels a lot longer (alt) + code:8194D8:FF + +cartridge sha256:2ec71aca4efc3791b6b3e65956df3eafd2a46e223d5ea71aead07d30ca48b6c9 + title:Operation Starfi5h (Europe) + cheat + description:Infinite health + code:7EFB05:03 + cheat + description:Infinite lives + code:7EFB03:03 + +cartridge sha256:5cbed0401734142184166917427d24f9e5f107a7adea665e2f4b4101491ad54b + title:Operation Thunderbolt (USA) + cheat + description:Infinite health + code:7E36EA:63 + cheat + description:Infinite Bullets + code:7E36ED:09 + cheat + description:Infinite Rockets + code:7E36EF:09 + cheat + description:Infinite Clips + code:7E36EE:09 + +cartridge sha256:0c08e6b817e4d0b333acb910a0bde3d79bd2dc188defc5df9a7c1233fa81c98d + title:Oscar (USA) + cheat + description:Invincibility + code:7E0320:03 + cheat + description:Invincibility (alt) + code:7E05B6:FF + cheat + description:Infinite lives + code:7E0322:0A + cheat + description:All Oscars found + code:7E0324:00 + cheat + description:No Oscars to find + code:7E0324:00 + +cartridge sha256:db44f8b58a31b640a47aa4390101c3c6a5f613e4e49c636d44786278033dec19 + title:Outlander (USA) + cheat + description:Infinite health while in the car + code:C260-CF07+C260-6F07 + cheat + description:Almost infinite health while out of the car (except when you eat poisonous food) + code:C9B6-450D + cheat + description:Infinite handgun ammo + code:DD69-45A4 + cheat + description:Infinite surface-to-air missiles on pick-up + code:C285-C7D9 + cheat + description:Car ammo worth nothing on pick-up + code:DD67-C1A4 + cheat + description:Car ammo worth more on pick-up + code:D467-C5D4 + cheat + description:Water worth nothing on pick-up + code:DD63-C0A4 + cheat + description:Water worth more on pick-up + code:DF63-C9D4 + cheat + description:Hand gun ammo worth nothing on pick-up + code:DD66-C064 + cheat + description:Food worth nothing on pick-up + code:DD6A-C0D4 + cheat + description:Gas can worth nothing on pick-up + code:DD6F-C004 + cheat + description:Gas can worth more on pick-up + code:D46F-C064 + cheat + description:Start with more car ammo + code:D980-47A1 + cheat + description:Start with less car ammo + code:DD80-47A1 + cheat + description:Start with more handgun ammo + code:1A89-4FD1 + cheat + description:Start with less handgun ammo + code:FD89-4FD1 + cheat + description:Start with more fuel + code:D480-4F61 + +cartridge sha256:582548dc86598a3557e9e3c27285c81964b006a954affe5c73948da5375ea11c + title:Out of This World (USA) + cheat + description:First three shields are infinite + code:7E0D84:E7+7E0D8A:E7+7E0D90:E7 + cheat + description:Infinite ammo in levels that have guns + code:7E0C4E:80+7E0C4F:80 + +cartridge sha256:54b2f03393109ac7fd36d8c7752f15a44d9607ab0187a371b853191db3592c01 + title:Out to Lunch (USA) + cheat + description:Infinite lives + code:7E0088:63 + cheat + description:Score modifier + code:7E0009:63 + +cartridge sha256:10c8abce67b49f8afbe880d2f13e0fd6d5efc162df34d5941e4a94851f23b2ff + title:Pac-Attack (USA) + cheat + description:Fairy bar is always full (normal mode) + code:7E160E:FF + +cartridge sha256:7fe4cb9c294d66589ff78e225774471ecb7db80df25f2b6199ca25671358072b + title:Pac-in-Time (USA) + cheat + description:Infinite health + code:7E1533:BF + cheat + description:Infinite lives + code:7E0AD5:02 + cheat + description:Instant exit + code:7E0B03:00 + +cartridge sha256:4cb52ba751c42d9e12ca429e5d657622a370b608002880a997f64de453f0de20 + title:Pac-Man 2 - The New Adventures (USA) + cheat + description:Infinite power pellets + code:C288-3FDB + cheat + description:Have Rope-Way and Train Pass + code:7E0500:04 + cheat + description:Have all 3 Power Pellets + code:7E0506:03 + cheat + description:Have all 3 Cartridges + code:7E0507:07 + cheat + description:Have all 3 I.D. Cards + code:7E0508:07 + cheat + description:Have Milk + code:7E0509:01 + +cartridge sha256:46286d0839a4397fc4c067b39783f98d2aefeca870a468bae601a1434f1dde90 + title:Paladin's Quest (USA) + cheat + description:Level 99 after one battle + code:6D63-6701+6D6E-6401 + cheat + description:Infinite health + code:10B5-6405 + cheat + description:Spells use up no HP + code:108E-AF00 + cheat + description:No money needed in toolhouse and weapon shop + code:BA88-6481 + cheat + description:No money needed in learning center + code:BA3A-04BE + cheat + description:Spell power increases at 2x normal rate + code:D063-D401 + cheat + description:Spell power increases at 3x normal rate + code:D163-D401 + cheat + description:Chezni starts with 255 max HP + code:EEEB-6D1F + cheat + description:Chezni starts with 255 present HP + code:EEE6-673F + cheat + description:Chezni starts with 40 Power, 42 Attack + code:46EB-6D3F + cheat + description:Chezni starts with 60 Power, 62 Attack + code:7AEB-6D3F + cheat + description:Chezni starts with 42 Defense, 30 Endurance + code:F3EB-6F3F + cheat + description:Chezni starts with 72 Defense, 60 Endurance + code:7AEB-6F3F + cheat + description:Chezni starts with 30 Speed + code:F3EB-6F1F + cheat + description:Chezni starts with 60 Speed + code:7AEB-6F1F + cheat + description:Chezni starts with a bow + code:D6EA-6F1D + cheat + description:Chezni starts with a light sword + code:D2EA-6F1D + cheat + description:Chezni starts with a mid sword + code:FDEA-6F1D + cheat + description:Chezni starts with a Aybro Spear + code:FCEA-6F1D + cheat + description:Chezni starts with a heavy sword + code:F5EA-6F1D + cheat + description:Chezni starts with a wind sword + code:7DEA-6F1D + cheat + description:Chezni starts with HST + code:70EA-6F1D + cheat + description:Chezni starts with Gomutai + code:9FEA-6F1D + cheat + description:Chezni starts with a Psych Beam + code:54EA-6F1D + cheat + description:Chezni starts with a flame thrower + code:57EA-6F1D + cheat + description:Chezni starts with light armor + code:D8EA-6FCD + cheat + description:Chezni starts with mid armor + code:DEEA-6FCD + cheat + description:Chezni starts with heavy armor + code:FAEA-6FCD + cheat + description:Chezni starts with storm armor + code:7FEA-6FCD + cheat + description:Chezni starts with bib + code:77EA-6FCD + cheat + description:Chezni starts with wood boots + code:D4EA-6F3D + cheat + description:Chezni starts with long boots + code:F8EA-6F3D + cheat + description:Chezni starts with knife boots + code:40EA-6F3D + cheat + description:Chezni starts with mid boots + code:F9EA-6F3D + cheat + description:Chezni starts with sun helm + code:74EA-6D3D + cheat + description:Chezni starts with leather helm + code:D9EA-6D3D + cheat + description:Chezni starts with helmet + code:DAEA-6D3D + cheat + description:Chezni starts with rage helmet + code:4AEA-6D3D + cheat + description:Chezni starts with power helmet + code:F1EA-6D3D + cheat + description:Chezni starts with cosmo helmet + code:55EA-6D3D + cheat + description:Chezni starts with gabni shield + code:79EA-6F4D + cheat + description:Chezni starts with leather shield + code:71EA-6F4D + cheat + description:Chezni starts with pick-axe + code:DBEA-6F4D + cheat + description:Chezni starts with gauntlet + code:F0EA-6F4D + cheat + description:Chezni starts with fire shield + code:FBEA-6F4D + cheat + description:Chezni starts with Rft shield + code:59EA-6F4D + cheat + description:No random battles + code:7E1868:09 + cheat + description:Infinite high gold + code:7E17C3:0E + cheat + description:Character 1 - level 99 + code:7E15FA:63 + cheat + description:Character 1 - 9999 current HP + code:7E15FE:0F+7E15FF:27 + cheat + description:Character 1 - 9999 max HP + code:7E1600:0F+7E1601:27 + cheat + description:Character 1 - 999 Power/Attack + code:7E1602:E7+7E1603:03 + cheat + description:Character 1 - 999 SP/Attack SP + code:7E1604:E7+7E1605:03 + cheat + description:Character 1 - 999 Defense/Endurance + code:7E1606:E7+7E1607:03 + cheat + description:Character 1 - 999 Luck + code:7E1608:E7+7E1608:03 + cheat + description:Character 1 - 99 available Magic + code:7E160F:63 + cheat + description:Character 1 - 127 E Spirit + code:7E1610:7F + cheat + description:Character 1 - 127 W Spirit + code:7E1611:7F + cheat + description:Character 1 - 127 F Spirit + code:7E1612:7F + cheat + description:Character 1 - 127 Sk Spirit + code:7E1613:7F + cheat + description:Character 1 - 127 L Spirit + code:7E1614:7F + cheat + description:Character 1 - 127 A Spirit + code:7E1615:7F + cheat + description:Character 1 - 127 MT Spirit + code:7E1616:7F + cheat + description:Character 1 - 127 SP Spirit + code:7E1617:7F + cheat + description:Character 1 - 25 spells + code:7E16DD:25 + cheat + description:Character 2 - level 99 + code:7E1620:63 + cheat + description:Character 2 - 9999 current HP + code:7E1624:0F+7E1625:27 + cheat + description:Character 2 - 9999 max HP + code:7E1626:0F+7E1627:27 + cheat + description:Character 2 - 999 Power/Attack + code:7E1628:E7+7E1629:03 + cheat + description:Character 2 - 999 SP/Attack SP + code:7E162A:E7+7E162B:03 + cheat + description:Character 2 - 999 Defense/Endurance + code:7E162C:E7+7E162D:03 + cheat + description:Character 2 - 999 Luck + code:7E162E:E7+7E162E:03 + cheat + description:Character 2 - 99 available Magic + code:7E1635:63 + cheat + description:Character 2 - 127 E Spirit + code:7E1636:7F + cheat + description:Character 2 - 127 W Spirit + code:7E1637:7F + cheat + description:Character 2 - 127 F Spirit + code:7E1638:7F + cheat + description:Character 2 - 127 Sk Spirit + code:7E1639:7F + cheat + description:Character 2 - 127 L Spirit + code:7E163A:7F + cheat + description:Character 2 - 127 A Spirit + code:7E163B:7F + cheat + description:Character 2 - 127 MT Spirit + code:7E163C:7F + cheat + description:Character 2 - 127 SP Spirit + code:7E163D:7F + cheat + description:Character 2 - 25 spells + code:7E1703:25 + cheat + description:Character 3 - level 99 + code:7E1646:63 + cheat + description:Character 3 - 9999 current HP + code:7E164A:0F+7E164B:27 + cheat + description:Character 3 - 9999 max HP + code:7E164C:0F+7E164D:27 + cheat + description:Character 3 - 999 Power/Attack + code:7E164E:E7+7E164F:03 + cheat + description:Character 3 - 999 SP/Attack SP + code:7E1650:E7+7E1651:03 + cheat + description:Character 3 - 999 Defense/Endurance + code:7E1652:E7+7E1653:03 + cheat + description:Character 3 - 999 Luck + code:7E1654:E7+7E1654:03 + cheat + description:Character 3 - 99 available Magic + code:7E165B:63 + cheat + description:Character 3 - 127 E Spirit + code:7E165C:7F + cheat + description:Character 3 - 127 W Spirit + code:7E165D:7F + cheat + description:Character 3 - 127 F Spirit + code:7E165E:7F + cheat + description:Character 3 - 127 Sk Spirit + code:7E165F:7F + cheat + description:Character 3 - 127 L Spirit + code:7E1660:7F + cheat + description:Character 3 - 127 A Spirit + code:7E1661:7F + cheat + description:Character 3 - 127 MT Spirit + code:7E1662:7F + cheat + description:Character 3 - 127 SP Spirit + code:7E1663:7F + cheat + description:Character 3 - 25 spells + code:7E1729:25 + cheat + description:Character 4 - level 99 + code:7E166C:63 + cheat + description:Character 4 - 9999 current HP + code:7E1670:0F+7E1671:27 + cheat + description:Character 4 - 9999 max HP + code:7E1672:0F+7E1673:27 + cheat + description:Character 4 - 999 Power/Attack + code:7E1674:E7+7E1675:03 + cheat + description:Character 4 - 999 SP/Attack SP + code:7E1676:E7+7E1677:03 + cheat + description:Character 4 - 999 Defense/Endurance + code:7E1678:E7+7E1679:03 + cheat + description:Character 4 - 999 Luck + code:7E167A:E7+7E167A:03 + cheat + description:Character 4 - 99 available Magic + code:7E1681:63 + cheat + description:Character 4 - 127 E Spirit + code:7E1682:7F + cheat + description:Character 4 - 127 W Spirit + code:7E1683:7F + cheat + description:Character 4 - 127 F Spirit + code:7E1684:7F + cheat + description:Character 4 - 127 Sk Spirit + code:7E1685:7F + cheat + description:Character 4 - 127 L Spirit + code:7E1686:7F + cheat + description:Character 4 - 127 A Spirit + code:7E1687:7F + cheat + description:Character 4 - 127 MT Spirit + code:7E1688:7F + cheat + description:Character 4 - 127 SP Spirit + code:7E1689:7F + cheat + description:Character 4 - 25 spells + code:7E174F:25 + +cartridge sha256:7cec4ffc3eda0441561717cf55927901b5fbbd669c254079f78ca74c67c4a17b + title:Paperboy 2 (USA) + cheat + description:Infinite papers + code:DD88-D464 + cheat + description:Infinite time in training course + code:DD67-D4D9 + cheat + description:Infinite lives (game still ends when all subscriptions are canceled) + code:DDBE-6404 + cheat + description:Paper bundles worth 0 if you have less than 10 + code:DD6D-6F60 + cheat + description:Paper bundles worth 5 if you have less than 10 + code:D96D-6F60 + cheat + description:Paper bundles worth 20 if you have less than 10 + code:F06D-6F60 + cheat + description:Paper bundles worth 30 if you have less than 10 + code:F36D-6F60 + cheat + description:Paper bundles worth 40 if you have less than 10 + code:466D-6F60 + cheat + description:Paper bundles worth 50 if you have less than 10 + code:746D-6F60 + cheat + description:Continue next life with 1 paper if you had less than 10 + code:DFC1-0FAF + cheat + description:Continue next life with 5 papers if you had less than 10 + code:D9C1-0FAF + cheat + description:Continue next life with 20 papers if you had less than 10 + code:F0C1-0FAF + cheat + description:Continue next life with 30 papers if you had less than 10 + code:F3C1-0FAF + cheat + description:Continue next life with 40 papers if you had less than 10 + code:46C1-0FAF + cheat + description:Continue next life with 50 papers if you had less than 10 + code:74C1-0FAF + cheat + description:Start with 79 seconds instead of 39 in Week 1 training course + code:DB6A-ADA0 + cheat + description:Start with 59 seconds in Week 1 training course + code:D56A-ADA0 + cheat + description:Start with 19 seconds in Week 1 training course + code:D76A-ADA0 + cheat + description:Start with 25 papers instead of 10 + code:FBC6-DFAD + cheat + description:Start with 50 papers + code:74C6-DFAD + cheat + description:Start with 99 papers + code:17C6-DFAD + cheat + description:Start with 1 life instead of 5 - Paperboy + code:DFBF-A767 + cheat + description:Start with 3 lives - Paperboy + code:D7BF-A767 + cheat + description:Start with 7 lives - Paperboy + code:D5BF-A767 + cheat + description:Start with 9 lives - Paperboy + code:DBBF-A767 + cheat + description:Start with 25 lives - Paperboy + code:FBBF-A767 + cheat + description:Start with 50 lives - Paperboy + code:74BF-A767 + cheat + description:Start with 99 lives - Paperboy + code:17BF-A767 + cheat + description:Start with 1 life instead of 5 - Papergirl + code:DFB5-ADD7 + cheat + description:Start with 3 lives - Papergirl + code:D7B5-ADD7 + cheat + description:Start with 7 lives - Papergirl + code:D5B5-ADD7 + cheat + description:Start with 9 lives - Papergirl + code:DBB5-ADD7 + cheat + description:Start with 25 lives - Papergirl + code:FBB5-ADD7 + cheat + description:Start with 50 lives - Papergirl + code:74B5-ADD7 + cheat + description:Start with 99 lives - Papergirl + code:17B5-ADD7 + +cartridge sha256:14ad9d2fb8e6bb0f49bc9e53f3c472177653d1c24102169ade308a2fab8a8888 + title:Parodius da! - Shinwa kara Owarai e (Japan) + cheat + description:Infinite lives + code:7E0098:03 + +cartridge sha256:c414a4084b3d03aba19496d2efdd68fcf826194d8f1308f5c98e3a7af2fcc063 + title:Peace Keepers, The (USA) + cheat + description:Invincibility + code:C229-CF07 + cheat + description:Infinite health + code:6E31-4DAD+B031-4FDD+D131-4F0D+5331-4F6D + cheat + description:One hit kills + code:102C-C7D3 + +cartridge sha256:5c0b5266a191852ca593235f07180e673cb79e3f0b0dd31f65808eef83bf6e90 + title:PGA Tour Golf (USA) + cheat + description:Allow 14 clubs for full set instead of 13 + code:D235-6D07+D22A-D40F + cheat + description:Allow 15 clubs for full set + code:D335-6D07+D32A-D40F + cheat + description:Allow 16 clubs for full set + code:DE35-6D07+DE2A-D40F + cheat + description:No wind + code:6DC8-6DD7 + cheat + description:Constant wind of 10 mph + code:CBC8-6DD7+DDC8-6D67+DCC8-6D07 + cheat + description:Constant wind direction to the left + code:BACA-64D7 + cheat + description:Each round ends after hole 1 + code:DFA7-A704 + cheat + description:Each round ends after hole 2 + code:D4A7-A704 + cheat + description:Each round ends after hole 3 + code:D7A7-A704 + cheat + description:Each round ends after hole 4 + code:D0A7-A704 + cheat + description:Each round ends after hole 5 + code:D9A7-A704 + cheat + description:Each round ends after hole 6 + code:D1A7-A704 + cheat + description:Each round ends after hole 7 + code:D5A7-A704 + cheat + description:Each round ends after hole 8 + code:D6A7-A704 + cheat + description:Each round ends after hole 9 + code:DBA7-A704 + cheat + description:Each round ends after hole 10 + code:DCA7-A704 + cheat + description:Each round ends after hole 11 + code:D8A7-A704 + cheat + description:Each round ends after hole 12 + code:DAA7-A704 + cheat + description:Each round ends after hole 13 + code:D2A7-A704 + cheat + description:Each round ends after hole 14 + code:D3A7-A704 + cheat + description:Each round ends after hole 15 + code:DEA7-A704 + cheat + description:Each round ends after hole 16 + code:FDA7-A704 + cheat + description:Each round ends after hole 17 + code:FFA7-A704 + +cartridge sha256:0663330bc061f4b768fa1806610878ef6e6cf546f36041ae087c8e55703693b8 + title:Phalanx - The Enforce Fighter A-144 (USA) + cheat + description:Infinite health + code:3C21-AD0F + cheat + description:Infinite lives + code:DD2A-64AF + cheat + description:Infinite credits + code:DD63-DD04 + cheat + description:Hit anywhere + code:C230-6DDD+DD34-64DD+DD34-670D+DD3F-640D+DD3F-676D + cheat + description:Once power-up has been obtained, it is not lost until you continue (doesn't work for weapon, only power-ups) + code:C229-D7A4 + cheat + description:Power capsule restores armor to full strength + code:9D23-6DAF+6723-6FDF + cheat + description:Power capsule has no effect on armor or power-up + code:1D23-6D6F + cheat + description:Start with 1 credit instead of 4 + code:DFA8-05E3+DF2D-015A + cheat + description:Start with 2 credits + code:D4A8-05E3+D42D-015A + cheat + description:Start with 3 credits + code:D7A8-05E3+D72D-015A + cheat + description:Start with 5 credits + code:D9A8-05E3+D92D-015A + cheat + description:Start with 7 credits + code:D5A8-05E3+D52D-015A + cheat + description:Start with 10 credits + code:FDA8-05E3+FD2D-015A + cheat + description:Start with 1 life + code:DFA8-00E3+DF2D-008A + cheat + description:Start with 2 lives + code:D4A8-00E3+D42D-008A + cheat + description:Start with 3 lives + code:D7A8-00E3+D72D-008A + cheat + description:Start with 4 lives + code:D0A8-00E3+D02D-008A + cheat + description:Start with 6 lives + code:D1A8-00E3+D12D-008A + cheat + description:Start with 11 lives + code:FFA8-00E3+FF2D-008A + cheat + description:Start with 26 lives + code:41A8-00E3+412D-008A + cheat + description:Start with 51 lives + code:9FA8-00E3+9F2D-008A + cheat + description:Start with 100 lives + code:BCA8-00E3+BC2D-008A + cheat + description:Start on mission 2 + code:D42F-007A+D4AA-01E3 + cheat + description:Start on mission 3 + code:D72F-007A+D7AA-01E3 + cheat + description:Start on mission 4 + code:D02F-007A+D0AA-01E3 + cheat + description:Start on mission 5 + code:D92F-007A+D9AA-01E3 + cheat + description:Start on mission 6 + code:D12F-007A+D1AA-01E3 + cheat + description:Start on mission 7 + code:D52F-007A+D5AA-01E3 + cheat + description:Start on mission 8 + code:D62F-007A+D6AA-01E3 + cheat + description:After losing a life automatically finish level, gain 99 lives and retain all power-ups + code:00D83A:AD + cheat + description:Infinite lives (alt) + code:00D6CB:00 + +cartridge sha256:be1bf238d76b74bfcc0b86a899b8caedd0a49c105576c659b56045c85512a166 + title:Phantom 2040 (USA) (Beta) + cheat + description:Invincibility after first hit + code:3367-3760 + cheat + description:Infinite lives + code:C2AF-CFD9 + cheat + description:Infinite weapon energy + code:C2AA-14A9 + cheat + description:Access all weapons (highlight weapon and press X to equip) + code:B23B-34D9 + +cartridge sha256:b7291088f5c49e1fc55bf932076ec03f7b39f6e409ae06e884b57024c56cdc87 + title:Phantom 2040 (USA) + cheat + description:Invincibility + code:3365-3DD0+3361-34A0 + cheat + description:Infinite lives + code:62AF-34D9 + cheat + description:Infinite weapon energy + code:C2A2-CF69 + cheat + description:Access all weapons (highlight weapon and press X to equip) + code:233E-3FD9 + +cartridge sha256:03d0127f5de3237e22ad00de0c20763274da7b71142dde693240ac96d10983a3 + title:Pilotwings (USA) + cheat + description:Infinite fuel + code:108D-0FA7 + cheat + description:Infinite time (disable to detach hang glider from plane) + code:DD8E-AFD5 + cheat + description:Reduce gravity + code:4DE7-CD0F + cheat + description:Increase gravity + code:CDE7-CD0F + cheat + description:Increase rocket pack thrust power 3x + code:E2EF-6F0F + +cartridge sha256:3a52bf09850aa054dca443f7ea74d43f201dffecc40326924ecba9b0f1450e43 + title:Pinball Dreams (USA) + cheat + description:Slow motion + code:C763-3DD4 + cheat + description:Ball attracts to the top + code:13C9-CDDF + cheat + description:Ball attracts to the side + code:13CF-CDDF + cheat + description:Spastic ball + code:BECC-CD0F + +cartridge sha256:0888d20ab2f834c77b0a2dc2162c43890a1640adc78c6b0bb5892ca8d5008ad3 + title:Pinball Fantasies (USA) + cheat + description:Infinite balls + code:7E00B8:03 + +cartridge sha256:d0f4a5040ecf96dc49aa0084160e291a38f2ee75319750db4d6687ab36828da9 + title:Pink Goes to Hollywood (USA) + cheat + description:Invincibility + code:1DB0-C7AA+1DB9-3F62+1DB1-CFA2 + cheat + description:Invincibility (alt) + code:7E0201:FF + cheat + description:Infinite lives + code:7E01FF:03 + cheat + description:Infinite time + code:7E0203:09 + +cartridge sha256:fe7b861504886b40207d777cfc0dce76778b5fd8e679a67d04c9ded98cd1e59e + title:Pinocchio (Europe) + cheat + description:Infinite health + code:7E03D8:28 + cheat + description:Infinite lives + code:7E03DE:03 + +cartridge sha256:98c51c3bb577600fe79577c323333a791baa30904f37c695890e6e380b75e3c8 + title:Pinocchio (USA) + cheat + description:Infinite health + code:7E03D8:50 + cheat + description:Infinite lives + code:7E03DE:05 + +cartridge sha256:447dfa710e69479159e9d407474fbf5f67d3a3330ab0c7627afd123ded3fdb3a + title:Pirates of Dark Water, The (USA) + cheat + description:Invincibility + code:C28B-47D4 + cheat + description:Health refills about every 15 seconds + code:4F82-17AF+D583-1DDF + cheat + description:Infinite health + code:DD82-14AF + cheat + description:Infinite health (alt) + code:622B-37D8+CB2B-3468+962B-34A8 + cheat + description:Infinite special attacks (no health loss) + code:DDA5-1DDF + cheat + description:Infinite lives + code:C280-1F6F + cheat + description:One hit kills + code:3CAF-3DAF+3CAF-3FDF+CBAF-3F0F+5EAF-3F6F + cheat + description:1/2 health after 1st hit (1st life only) + code:4D65-1FF5+4D63-440E + cheat + description:Start with less health (after 1st life) + code:4DB0-CFDF + cheat + description:Start with 6 lives (not when joining in) + code:D9C8-4DA4 + cheat + description:Start with 2 lives (not when joining in) + code:DFC8-4DA4 + +cartridge sha256:c2a1a66648a0a0bfe2f201cf4f926d138e410fbf85ecf436ccb9aac70c0df3de + title:Pit-Fighter (USA) + cheat + description:Infinite super powers after gaining one + code:DD32-6700 + cheat + description:Executioner in match 1 has less health + code:10C6-07DF + cheat + description:Executioner in match 1 has more health + code:DFC6-070F + cheat + description:C.C. has less health in match 2 + code:10CB-07DF+DDCB-070F + cheat + description:C.C. has more health in match 2 + code:D4CB-070F + cheat + description:Angel has less health in match 3 + code:10C8-07DF + cheat + description:Angel has more health in match 3 + code:DFC8-070F + cheat + description:All opponents have less health + code:C485-0DD7+DD85-0D07+10C6-07DF + cheat + description:All opponents have more health + code:C485-0DD7+DD85-0D07+10C6-07DF+D4C6-070F + cheat + description:Start with more health + code:EEBF-A4D0 + cheat + description:Start with less health + code:74BF-A4D0 + cheat + description:Start with a lot more health + code:D4BF-A760 + cheat + description:Start with 3 super powers + code:D7B3-D769 + +cartridge sha256:e03d117d8b3093b0bbad5224638f85378b254b81eb304e506a732b4338802e0f + title:Pitfall - The Mayan Adventure (USA) + cheat + description:Infinite Stones of Pacal + code:DDA6-3D69 + cheat + description:Infinite Sling Stones + code:DDA5-1709 + cheat + description:Infinite Boomerangs + code:DDA5-3700 + cheat + description:Walk through walls + code:6D64-CDAF + cheat + description:Jump through ceilings + code:6D68-1FD4 + cheat + description:Get 2x energy from sacred hearts + code:746B-4D6A + cheat + description:Get 3x energy from sacred hearts + code:086B-4D6A + cheat + description:Sling stones do mega-damage + code:74A4-CF69 + cheat + description:Time keeper power-up lasts longer + code:ED6C-CDDA+D46C-CD0A + cheat + description:20 Stones of Pacal on pick-up + code:F06D-1D0A + cheat + description:Moon-jump + code:DD6F-C7A1 + cheat + description:Reset game to play original Pitfall infinitely + code:D3B5-1F0F + cheat + description:Replaces main game with original Pitfall + code:D389-4FAA + cheat + description:Start with 10 lives + code:DB6B-C4A1+DBC6-34DE + cheat + description:Start with 7 lives + code:D16B-C4A1+D1C6-34DE + cheat + description:Start with 2 lives + code:DF6B-C4A1+DFC6-34DE + cheat + description:Invincibility and invisibility + code:7E03CD:19 + cheat + description:Infinite health + code:7E10C1:FF + cheat + description:Infinite lives + code:7E00C0:03 + +cartridge sha256:72b2b3bead3fcd27a1610ad5d4d8be3235efeaff96df2e7858911992a5892d21 + title:Pocky & Rocky (USA) + cheat + description:Infinite health - Pocky + code:C933-A794 + cheat + description:Infinite health - Rocky + code:C93E-A797 + cheat + description:Infinite time + code:CB2D-DFDF + cheat + description:Infinite lives - Pocky + code:DDA7-AD65 + cheat + description:Infinite lives - Rocky + code:DD35-0761 + cheat + description:Weapons don't deplete when hit - Pocky + code:4032-A4F4 + cheat + description:Weapons don't deplete when hit - Pocky + code:4033-AFF7 + cheat + description:Blue ball acts as red ball - Pocky + code:D43F-6FF4 + cheat + description:Red ball acts as blue ball - Pocky + code:DF3D-6424 + cheat + description:Blue ball acts as red ball - Rocky + code:D43B-6F27 + cheat + description:Red ball acts as blue ball - Rocky + code:DF36-67B7 + cheat + description:9 lives stolen from Rocky (must have one life remaining) + code:DBAA-AD60 + cheat + description:9 lives stolen from Pocky (must have one life remaining) + code:DB3A-DD69 + cheat + description:Start with 1 life - Pocky + code:DF62-A7D4 + cheat + description:Start with 6 lives - Pocky + code:D162-A7D4 + cheat + description:Start with 9 lives - Pocky + code:DB62-A7D4 + cheat + description:Start with 1 life - Rocky + code:DF62-A704 + cheat + description:Start with 6 lives - Rocky + code:D162-A704 + cheat + description:Start with 9 lives - Rocky + code:DB62-A704 + cheat + description:Invincibility + code:01B67F:D0+01B67D:85 + cheat + description:Infinite health + code:7E0068:08 + cheat + description:Infinite time (alt) + code:7E0F12:9A + cheat + description:Infinite lives + code:7E006A:03 + cheat + description:Infinite Special + code:7E0066:02 + cheat + description:Infinite Shield + code:7E00E4:02 + +cartridge sha256:cc33ae02114ea18a86592de327b2b4bcc80728b11a5e4c61666dca71480d4169 + title:Pocky & Rocky 2 (USA) + cheat + description:Invincibility + code:039731:60+069739:60 + cheat + description:Infinite time + code:7E7064:76 + cheat + description:Infinite time (alt) + code:7E7064:79+7E7062:79+7E7060:79 + cheat + description:Infinite lives + code:7E19F4:03 + cheat + description:Infinite Keys + code:7E05B2:99 + cheat + description:Max Card + code:7E19F6:02 + cheat + description:Infinite hearts when riding Spirit Dog + code:7E19F2:05 + +cartridge sha256:000f4534a0376958edcc7ae3e6c5a7ea0dd6a775646207f60ad3923e27f110f3 + title:Pop'n TwinBee - Rainbow Bell Adventures (Europe) + cheat + description:Infinite health + code:7E02EC:64 + +cartridge sha256:5e580f220ed16281df8ee9a5f450b553f39f8c4078d3f3048d66bda15f98e19f + title:Populous (USA) + cheat + description:Allows you to select any world from the Conquer screen with the B and X buttons + code:DD30-64DD + cheat + description:Your population starts at 10 instead of 3 for battles 0-4 + code:DC6C-6F09 + cheat + description:Your population starts at 20 for battles 0-4 + code:F06C-6F09 + cheat + description:Your population starts at 30 for battles 0-4 + code:F36C-6F09 + cheat + description:His population starts at 10 instead of 3 for battles 0-4 + code:DC6C-6F69 + cheat + description:His population starts at 20 for battles 0-4 + code:F06C-6F69 + cheat + description:His population starts at 30 for battles 0-4 + code:F36C-6F69 + cheat + description:You have no Supreme Commands available for battles 0-4 + code:DD6C-6D69 + cheat + description:He has all Supreme Commands available for battles 0-4 + code:7E6C-6D09 + cheat + description:Your population starts at 10 instead of 3 for battles 5-9 + code:DC6C-67A9 + cheat + description:Your population starts at 20 for battles 5-9 + code:F06C-67A9 + cheat + description:Your population starts at 30 for battles 5-9 + code:F36C-67A9 + cheat + description:His population starts at 10 instead of 3 for battles 5-9 + code:DC68-6DD9 + cheat + description:His population starts at 20 for battles 5-9 + code:F068-6DD9 + cheat + description:His population starts at 30 for battles 5-9 + code:F368-6DD9 + cheat + description:You have no Supreme Commands available for battles 5-9 + code:DD6C-67D9 + cheat + description:He has all Supreme Commands available for battles 5-9 + code:7E6C-64A9 + cheat + description:Your population starts at 10 instead of 2 for battles 10-14 + code:DC68-6409 + cheat + description:Your population starts at 20 for battles 10-14 + code:F068-6409 + cheat + description:Your population starts at 30 for battles 10-14 + code:F368-6409 + cheat + description:His population starts at 10 instead of 2 for battles 10-14 + code:DC68-6469 + cheat + description:His population starts at 20 for battles 10-14 + code:F068-6469 + cheat + description:His population starts at 30 for battles 10-14 + code:F368-6469 + cheat + description:You have no Supreme Commands available for battles 10-14 + code:DD68-6F69 + cheat + description:He has all Supreme Commands available for battles 10-14 + code:7E68-6F09 + +cartridge sha256:ee9759fdb590ba908f569c2bb8a63703d282b58b84bd1fe0a472ea47685acdc5 + title:Porky Pig's Haunted Holiday (USA) + cheat + description:Invincibility (blinking) + code:C9C3-D708 + cheat + description:Don't flash after geting hit + code:DD26-D4DB + cheat + description:Don't flash as long after geting hit + code:F426-D4DB + cheat + description:Flash longer after geting hit + code:EE26-D4DB + cheat + description:Cupcakes are worth 0 + code:DD6F-6FDE + cheat + description:Cupcakes are worth 2 + code:D46F-6FDE + cheat + description:Cupcakes are worth 5 + code:D96F-6FDE + cheat + description:Cupcakes are worth 10 + code:DC6F-6FDE + cheat + description:Cupcakes are worth 15 + code:DE6F-6FDE + cheat + description:Start with 1 life + code:DDC6-DFAD + cheat + description:Start with 7 lives + code:D1C6-DFAD + cheat + description:Start with 10 lives + code:DBC6-DFAD + cheat + description:Start with 1 heart + code:DFC6-D46D + cheat + description:Start with 2 hearts + code:D4C6-D46D + cheat + description:Start with 8 hearts + code:D6C6-D46D + cheat + description:Start with 10 hearts + code:DCC6-D46D + cheat + description:Infinite health + code:7E0EAA:04 + cheat + description:Infinite Cupcakes + code:7E0E9F:63 + cheat + description:Infinite lives + code:7E0E9E:09 + +cartridge sha256:0288ec049723cd0c7f1148cdc1aef0b6922b8a756affe373c99d5690e0dfceaa + title:Power Piggs of the Dark Age (USA) + cheat + description:Invincibility + code:1DB7-C40F+6DB1-CF0D + cheat + description:Multi-jump + code:4066-CFA7+D5EA-44DC + cheat + description:Partial invincibility + code:7E06A4:3F + cheat + description:Infinite health + code:7E147E:00 + cheat + description:Infinite lives + code:7E1500:09 + cheat + description:Infinite Doughnuts + code:7E1505:09 + cheat + description:Start on level Beautiful Downtown Pigg + code:7E1874:00 + cheat + description:Start on level Dark Age Donut + code:7E1874:01 + cheat + description:Start on level North Blowhole Forest + code:7E1874:02 + cheat + description:Start on level Road to Wolff Castle + code:7E1874:03 + +cartridge sha256:8f387d083de1399bb79e5312c31a6f1757f2a536bfa25cecf1aea77bfd77058b + title:Prehistorik Man (USA) (En,Fr,Es) + cheat + description:Invincibility + code:7E00B6:03 + cheat + description:Infinite health + code:7E0558:03 + cheat + description:Infinite lives + code:7E0556:03 + cheat + description:Infinite Shout + code:7E056C:0A + cheat + description:Infinite ammo + code:7E0564:99 + cheat + description:Level modifier (first level must be cleared before the code actually works) + code:7E052A:## + cheat + description:Lots of bones + code:7E0560:99+7E0561:09 + cheat + description:Have 99 diamonds (disable after you finish the level) + code:7E0814:99 + +cartridge sha256:55376715f243b1bacd9aeecf1092bbc7837fe512592a2c1703d24b0829fc1934 + title:Primal Rage (USA) + cheat + description:Infinite time + code:C20F-E767 + cheat + description:Press down 3 times then start at the Start/Options screen for a hidden menu + code:D925-846F + cheat + description:Able to select as many credits as you want in the options screen + code:BB54-87AB + cheat + description:Select different times in the options screen + code:FD1D-7DD4 + cheat + description:Start with less health + code:0DA5-876D + cheat + description:Infinite health - P1 + code:7E1926:00 + cheat + description:Infinite health - P2 + code:7E1928:00 + cheat + description:One hit kills - P1 + code:7E210C:01 + cheat + description:One hit kills - P2 + code:7E210E:01 + cheat + description:Infinite fatality time + code:7E0270:00+7E02CE:54 + cheat + description:Freeplay activated + code:7E2114:01 + +cartridge sha256:494190cd6d7fd68882cbe255a6e237d9c4bdaf3988615ede0297a5e285ad5dd9 + title:Prince of Persia (USA) + cheat + description:Infinite time + code:6D32-0FA1+DC32-04D1 + cheat + description:Non-fatal injuries do no damage + code:BAA6-ADA5 + cheat + description:Non-fatal falls do no damage + code:43C9-6D61 + cheat + description:Non-fatal falls do 2 points of damage instead of 1 + code:D4C1-6701 + cheat + description:Falls do no damage except spikes (if you get stuck choose End Game and use a password to start the level over) + code:6DC0-6701 + cheat + description:All enemies have 1 health point + code:C260-A701+DF6C-DFA0 + cheat + description:All enemies have 2 health points + code:C260-A701+D46C-DFA0 + cheat + description:All enemies have 3 health points + code:C260-A701+D76C-DFA0 + cheat + description:All enemies have 4 health points + code:C260-A701+D06C-DFA0 + cheat + description:All enemies have 5 health points + code:C260-A701+D96C-DFA0 + cheat + description:All enemies have 10 health points + code:C260-A701+DC6C-DFA0 + cheat + description:Enemies defeated immediately (disable on bosses) + code:BA69-ADA1 + cheat + description:Start with 2 health points instead of 3 + code:D430-04A5 + cheat + description:Start with 4 health points + code:D030-04A5 + cheat + description:Start with 5 health points + code:D930-04A5 + cheat + description:Start with 6 health points + code:D130-04A5 + cheat + description:Start with 7 health points + code:D530-04A5 + cheat + description:Start with 8 health points + code:D630-04A5 + cheat + description:Start with 9 health points + code:DB30-04A5 + cheat + description:Start with 15 health points + code:FD30-04A5 + cheat + description:Start on level 2 + code:DFB7-D46E + cheat + description:Start on level 3 + code:D4B7-D46E + cheat + description:Start on level 4 + code:D7B7-D46E + cheat + description:Start on level 5 + code:D0B7-D46E + cheat + description:Start on level 6 + code:D9B7-D46E + cheat + description:Start on level 7 + code:D1B7-D46E + cheat + description:Start on level 8 + code:D5B7-D46E + cheat + description:Start on level 9 + code:D6B7-D46E + cheat + description:Start on level 10 + code:DBB7-D46E + cheat + description:Start on level 11 + code:DCB7-D46E + cheat + description:Start on level 12 + code:D8B7-D46E + cheat + description:Start on level 13 + code:DAB7-D46E + cheat + description:Start on level 14 + code:D2B7-D46E + cheat + description:Start on level 15 + code:D3B7-D46E + cheat + description:Start on level 16 + code:DEB7-D46E + cheat + description:Start on level 17 + code:FDB7-D46E + cheat + description:Start on level 18 + code:FFB7-D46E + cheat + description:Start on level 19 + code:F4B7-D46E + cheat + description:Start on level 20 + code:F7B7-D46E + +cartridge sha256:04ca1a481093c4a7e12f18b33697d6e05e50e30e0f5b1655aa265abd14719bba + title:Prince of Persia 2 - The Shadow & The Flame (USA) + cheat + description:Infinite health + code:7E0957:03 + cheat + description:Infinite time + code:7E0B98:69 + +cartridge sha256:65f7123ab4fc9bad24b1976da8e84976cc6977861626a05d4e2cce132ef3fd42 + title:Psycho Dream (Japan) + cheat + description:Invincibility (blinking) + code:DDB7-8D6D + cheat + description:Infinite time + code:DD7F-7407 + cheat + description:Infinite magic + code:69BE-77DF + cheat + description:Hit anywhere + code:6DDD-E71F+6DD4-EDCF+6DD7-EF3F+6DD0-E74F + cheat + description:Best weapon on pick-up + code:CBC7-74AD + +cartridge sha256:475c9baa1c2b76a6b3119e47d32814dc1c08e84e23250ae015bb0bccea915637 + title:Push-Over (USA) + cheat + description:Still can complete level even if time runs out + code:6D6B-6F0F + cheat + description:Tokens aren't lost when used to undo a push + code:3366-6F0F + cheat + description:Tokens aren't lost when used to advance when time runs out + code:3367-A4AF + cheat + description:Start on level 2 + code:CB66-AD6F+6266-AF0F+DF66-ADAF + cheat + description:Start on level 3 + code:CB66-AD6F+6266-AF0F+D466-ADAF + cheat + description:Start on level 4 + code:CB66-AD6F+6266-AF0F+D766-ADAF + cheat + description:Start on level 5 + code:CB66-AD6F+6266-AF0F+D066-ADAF + cheat + description:Start on level 6 + code:CB66-AD6F+6266-AF0F+D966-ADAF + cheat + description:Start on level 7 + code:CB66-AD6F+6266-AF0F+D166-ADAF + cheat + description:Start on level 8 + code:CB66-AD6F+6266-AF0F+D566-ADAF + cheat + description:Start on level 9 + code:CB66-AD6F+6266-AF0F+D666-ADAF + cheat + description:Start on level 10 + code:CB66-AD6F+6266-AF0F+DB66-ADAF + cheat + description:Start on level 11 + code:CB66-AD6F+6266-AF0F+DC66-ADAF + cheat + description:Start on level 12 + code:CB66-AD6F+6266-AF0F+D866-ADAF + cheat + description:Start on level 13 + code:CB66-AD6F+6266-AF0F+DA66-ADAF + cheat + description:Start on level 14 + code:CB66-AD6F+6266-AF0F+D266-ADAF + cheat + description:Start on level 15 + code:CB66-AD6F+6266-AF0F+D366-ADAF + cheat + description:Start on level 16 + code:CB66-AD6F+6266-AF0F+DE66-ADAF + cheat + description:Start on level 17 + code:CB66-AD6F+6266-AF0F+FD66-ADAF + cheat + description:Start on level 18 + code:CB66-AD6F+6266-AF0F+FF66-ADAF + cheat + description:Start on level 19 + code:CB66-AD6F+6266-AF0F+F466-ADAF + cheat + description:Start on level 20 + code:CB66-AD6F+6266-AF0F+F766-ADAF + cheat + description:Start on level 21 + code:CB66-AD6F+6266-AF0F+F066-ADAF + cheat + description:Start on level 22 + code:CB66-AD6F+6266-AF0F+F966-ADAF + cheat + description:Start on level 23 + code:CB66-AD6F+6266-AF0F+F166-ADAF + cheat + description:Start on level 24 + code:CB66-AD6F+6266-AF0F+F566-ADAF + cheat + description:Start on level 25 + code:CB66-AD6F+6266-AF0F+F666-ADAF + cheat + description:Start on level 26 + code:CB66-AD6F+6266-AF0F+FB66-ADAF + cheat + description:Start on level 27 + code:CB66-AD6F+6266-AF0F+FC66-ADAF + cheat + description:Start on level 28 + code:CB66-AD6F+6266-AF0F+F866-ADAF + cheat + description:Start on level 29 + code:CB66-AD6F+6266-AF0F+FA66-ADAF + cheat + description:Start on level 30 + code:CB66-AD6F+6266-AF0F+F266-ADAF + cheat + description:Start on level 31 + code:CB66-AD6F+6266-AF0F+F366-ADAF + cheat + description:Start on level 32 + code:CB66-AD6F+6266-AF0F+FE66-ADAF + cheat + description:Start on level 33 + code:CB66-AD6F+6266-AF0F+4D66-ADAF + cheat + description:Start on level 34 + code:CB66-AD6F+6266-AF0F+4F66-ADAF + cheat + description:Start on level 35 + code:CB66-AD6F+6266-AF0F+4466-ADAF + cheat + description:Start on level 36 + code:CB66-AD6F+6266-AF0F+4766-ADAF + cheat + description:Start on level 37 + code:CB66-AD6F+6266-AF0F+4066-ADAF + cheat + description:Start on level 38 + code:CB66-AD6F+6266-AF0F+4966-ADAF + cheat + description:Start on level 39 + code:CB66-AD6F+6266-AF0F+4166-ADAF + cheat + description:Start on level 40 + code:CB66-AD6F+6266-AF0F+4566-ADAF + cheat + description:Start on level 41 + code:CB66-AD6F+6266-AF0F+4666-ADAF + cheat + description:Start on level 42 + code:CB66-AD6F+6266-AF0F+4B66-ADAF + cheat + description:Start on level 43 + code:CB66-AD6F+6266-AF0F+4C66-ADAF + cheat + description:Start on level 44 + code:CB66-AD6F+6266-AF0F+4866-ADAF + cheat + description:Start on level 45 + code:CB66-AD6F+6266-AF0F+4A66-ADAF + cheat + description:Start on level 46 + code:CB66-AD6F+6266-AF0F+4266-ADAF + cheat + description:Start on level 47 + code:CB66-AD6F+6266-AF0F+4366-ADAF + cheat + description:Start on level 48 + code:CB66-AD6F+6266-AF0F+4E66-ADAF + cheat + description:Start on level 49 + code:CB66-AD6F+6266-AF0F+7D66-ADAF + cheat + description:Start on level 50 + code:CB66-AD6F+6266-AF0F+7F66-ADAF + cheat + description:Start on level 51 + code:CB66-AD6F+6266-AF0F+7466-ADAF + cheat + description:Start on level 52 + code:CB66-AD6F+6266-AF0F+7766-ADAF + cheat + description:Start on level 53 + code:CB66-AD6F+6266-AF0F+7066-ADAF + cheat + description:Start on level 54 + code:CB66-AD6F+6266-AF0F+7966-ADAF + cheat + description:Start on level 55 + code:CB66-AD6F+6266-AF0F+7166-ADAF + cheat + description:Start on level 56 + code:CB66-AD6F+6266-AF0F+7566-ADAF + cheat + description:Start on level 57 + code:CB66-AD6F+6266-AF0F+7666-ADAF + cheat + description:Start on level 58 + code:CB66-AD6F+6266-AF0F+7B66-ADAF + cheat + description:Start on level 59 + code:CB66-AD6F+6266-AF0F+7C66-ADAF + cheat + description:Start on level 60 + code:CB66-AD6F+6266-AF0F+7866-ADAF + cheat + description:Start on level 61 + code:CB66-AD6F+6266-AF0F+7A66-ADAF + cheat + description:Start on level 62 + code:CB66-AD6F+6266-AF0F+7266-ADAF + cheat + description:Start on level 63 + code:CB66-AD6F+6266-AF0F+7366-ADAF + cheat + description:Start on level 64 + code:CB66-AD6F+6266-AF0F+7E66-ADAF + cheat + description:Start on level 65 + code:CB66-AD6F+6266-AF0F+0D66-ADAF + cheat + description:Start on level 66 + code:CB66-AD6F+6266-AF0F+0F66-ADAF + cheat + description:Start on level 67 + code:CB66-AD6F+6266-AF0F+0466-ADAF + cheat + description:Start on level 68 + code:CB66-AD6F+6266-AF0F+0766-ADAF + cheat + description:Start on level 69 + code:CB66-AD6F+6266-AF0F+0066-ADAF + cheat + description:Start on level 70 + code:CB66-AD6F+6266-AF0F+0966-ADAF + cheat + description:Start on level 71 + code:CB66-AD6F+6266-AF0F+0166-ADAF + cheat + description:Start on level 72 + code:CB66-AD6F+6266-AF0F+0566-ADAF + cheat + description:Start on level 73 + code:CB66-AD6F+6266-AF0F+0666-ADAF + cheat + description:Start on level 74 + code:CB66-AD6F+6266-AF0F+0B66-ADAF + cheat + description:Start on level 75 + code:CB66-AD6F+6266-AF0F+0C66-ADAF + cheat + description:Start on level 76 + code:CB66-AD6F+6266-AF0F+0866-ADAF + cheat + description:Start on level 77 + code:CB66-AD6F+6266-AF0F+0A66-ADAF + cheat + description:Start on level 78 + code:CB66-AD6F+6266-AF0F+0266-ADAF + cheat + description:Start on level 79 + code:CB66-AD6F+6266-AF0F+0366-ADAF + cheat + description:Start on level 80 + code:CB66-AD6F+6266-AF0F+0E66-ADAF + cheat + description:Start on level 81 + code:CB66-AD6F+6266-AF0F+9D66-ADAF + cheat + description:Start on level 82 + code:CB66-AD6F+6266-AF0F+9F66-ADAF + cheat + description:Start on level 83 + code:CB66-AD6F+6266-AF0F+9466-ADAF + cheat + description:Start on level 84 + code:CB66-AD6F+6266-AF0F+9766-ADAF + cheat + description:Start on level 85 + code:CB66-AD6F+6266-AF0F+9066-ADAF + cheat + description:Start on level 86 + code:CB66-AD6F+6266-AF0F+9966-ADAF + cheat + description:Start on level 87 + code:CB66-AD6F+6266-AF0F+9166-ADAF + cheat + description:Start on level 88 + code:CB66-AD6F+6266-AF0F+9566-ADAF + cheat + description:Start on level 89 + code:CB66-AD6F+6266-AF0F+9666-ADAF + cheat + description:Start on level 90 + code:CB66-AD6F+6266-AF0F+9B66-ADAF + cheat + description:Start on level 91 + code:CB66-AD6F+6266-AF0F+9C66-ADAF + cheat + description:Start on level 92 + code:CB66-AD6F+6266-AF0F+9866-ADAF + cheat + description:Start on level 93 + code:CB66-AD6F+6266-AF0F+9A66-ADAF + cheat + description:Start on level 94 + code:CB66-AD6F+6266-AF0F+9266-ADAF + cheat + description:Start on level 95 + code:CB66-AD6F+6266-AF0F+9366-ADAF + cheat + description:Start on level 96 + code:CB66-AD6F+6266-AF0F+9E66-ADAF + cheat + description:Start on level 97 + code:CB66-AD6F+6266-AF0F+1D66-ADAF + cheat + description:Start on level 98 + code:CB66-AD6F+6266-AF0F+1F66-ADAF + cheat + description:Start on level 99 + code:CB66-AD6F+6266-AF0F+1466-ADAF + +cartridge sha256:89d57bf308033ef17f770a80080cbeed2d112244635d5b5f860f2016398cd2f6 + title:Q-bert 3 (USA) + cheat + description:Infinite lives + code:C2C5-AF6F + cheat + description:Start with 1 life instead of 5 + code:DF66-D7DD + cheat + description:Start with 3 lives + code:D766-D7DD + cheat + description:Start with 7 lives + code:D566-D7DD + cheat + description:Start with 9 lives + code:DB66-D7DD + cheat + description:Start with 25 lives + code:FB66-D7DD + cheat + description:Start with 100 lives + code:1066-D7DD + cheat + description:Start on level 1-2 + code:DF61-D76D + cheat + description:Start on level 1-3 + code:D461-D76D + cheat + description:Start on level 1-4 + code:D761-D76D + cheat + description:Start on level 2-1 + code:D061-D76D + cheat + description:Start on level 2-2 + code:D961-D76D + cheat + description:Start on level 2-3 + code:D161-D76D + cheat + description:Start on level 2-4 + code:D561-D76D + cheat + description:Start on level 3-1 + code:D661-D76D + cheat + description:Start on level 3-2 + code:DB61-D76D + cheat + description:Start on level 3-3 + code:DC61-D76D + cheat + description:Start on level 3-4 + code:D861-D76D + cheat + description:Start on level 4-1 + code:DA61-D76D + cheat + description:Start on level 4-2 + code:D261-D76D + cheat + description:Start on level 4-3 + code:D361-D76D + cheat + description:Start on level 4-4 + code:DE61-D76D + cheat + description:Start on level 5-1 + code:FD61-D76D + cheat + description:Start on level 5-2 + code:FF61-D76D + cheat + description:Start on level 5-3 + code:F461-D76D + cheat + description:Start on level 5-4 + code:F761-D76D + cheat + description:Start on level 6-1 + code:F061-D76D + cheat + description:Start on level 6-2 + code:F961-D76D + cheat + description:Start on level 6-3 + code:F161-D76D + cheat + description:Start on level 6-4 + code:F561-D76D + cheat + description:Start on level 7-1 + code:F661-D76D + cheat + description:Start on level 7-2 + code:FB61-D76D + cheat + description:Start on level 7-3 + code:FC61-D76D + cheat + description:Start on level 7-4 + code:F861-D76D + cheat + description:Start on level 8-1 + code:FA61-D76D + cheat + description:Start on level 8-2 + code:F261-D76D + cheat + description:Start on level 8-3 + code:F361-D76D + cheat + description:Start on level 8-4 + code:FE61-D76D + cheat + description:Start on level 9-1 + code:4D61-D76D + cheat + description:Start on level 9-2 + code:4F61-D76D + cheat + description:Start on level 9-3 + code:4461-D76D + cheat + description:Start on level 9-4 + code:4761-D76D + cheat + description:Start on level 10-1 + code:4061-D76D + cheat + description:Start on level 10-2 + code:4961-D76D + cheat + description:Start on level 10-3 + code:4161-D76D + cheat + description:Start on level 10-4 + code:4561-D76D + cheat + description:Start on level 11-1 + code:4661-D76D + cheat + description:Start on level 11-2 + code:4B61-D76D + cheat + description:Start on level 11-3 + code:4C61-D76D + cheat + description:Start on level 11-4 + code:4861-D76D + cheat + description:Start on level 12-1 + code:4A61-D76D + cheat + description:Start on level 12-2 + code:4261-D76D + cheat + description:Start on level 12-3 + code:4361-D76D + cheat + description:Start on level 12-4 + code:4E61-D76D + cheat + description:Start on level 13-1 + code:7D61-D76D + cheat + description:Start on level 13-2 + code:7F61-D76D + cheat + description:Start on level 13-3 + code:7461-D76D + cheat + description:Start on level 13-4 + code:7761-D76D + cheat + description:Start on level 14-1 + code:7061-D76D + cheat + description:Start on level 14-2 + code:7961-D76D + cheat + description:Start on level 14-3 + code:7161-D76D + cheat + description:Start on level 14-4 + code:7561-D76D + cheat + description:Start on level 15-1 + code:7661-D76D + cheat + description:Start on level 15-2 + code:7B61-D76D + cheat + description:Start on level 15-3 + code:7C61-D76D + cheat + description:Start on level 15-4 + code:7861-D76D + cheat + description:Start on level 16-1 + code:7A61-D76D + cheat + description:Start on level 16-2 + code:7261-D76D + cheat + description:Start on level 16-3 + code:7361-D76D + cheat + description:Start on level 16-4 + code:7E61-D76D + cheat + description:Start on level 17-1 + code:0D61-D76D + cheat + description:Start on level 17-2 + code:0F61-D76D + cheat + description:Start on level 17-3 + code:0461-D76D + cheat + description:Start on level 17-4 + code:0761-D76D + cheat + description:Start on level 18-1 + code:0061-D76D + cheat + description:Start on level 18-2 + code:0961-D76D + cheat + description:Start on level 18-3 + code:0161-D76D + cheat + description:Start on level 18-4 + code:0561-D76D + cheat + description:Start on level 19-1 + code:0661-D76D + cheat + description:Start on level 19-2 + code:0B61-D76D + cheat + description:Start on level 19-3 + code:0C61-D76D + cheat + description:Start on level 19-4 + code:0861-D76D + cheat + description:Start on level 20-1 + code:0A61-D76D + cheat + description:Start on level 20-2 + code:0261-D76D + cheat + description:Start on level 20-3 + code:0361-D76D + cheat + description:Start on level 20-4 + code:0E61-D76D + cheat + description:Start on level x1 + code:9D61-D76D + cheat + description:Start on level x2 + code:9F61-D76D + cheat + description:Start on level x3 + code:9461-D76D + cheat + description:Start on level x4 + code:9761-D76D + cheat + description:Start on level x5 + code:9061-D76D + cheat + description:Start on level x6 + code:9961-D76D + cheat + description:Start on level x7 + code:9161-D76D + cheat + description:Start on level x8 + code:9561-D76D + cheat + description:Start on level x9 + code:9661-D76D + cheat + description:Start on level x10 + code:9B61-D76D + cheat + description:Start on level x11 + code:9C61-D76D + cheat + description:Start on level x12 + code:9861-D76D + cheat + description:Start on level x13 + code:9A61-D76D + cheat + description:Start on level x14 + code:9261-D76D + cheat + description:Start on level x15 + code:9361-D76D + cheat + description:Start on level x16 + code:9E61-D76D + cheat + description:Start on level x17 + code:1D61-D76D + cheat + description:Start on level x18 + code:1F61-D76D + cheat + description:Start on level x19 + code:1461-D76D + cheat + description:Start on level x20 + code:1761-D76D + +cartridge sha256:4d6c7d6d2693d8d43bafaff7582f9a94885362dadd9ee4012bbbdce1ba10c30e + title:R-Type III - The Third Lightning (USA) + cheat + description:Invincibility + code:DD62-33DD + cheat + description:Infinite lives + code:C26B-C7D0 + cheat + description:Start at speed level 3 + code:DA6F-CE0D + cheat + description:Start at speed level 4 + code:FD6F-CE0D + cheat + description:Start at speed level 5 + code:F06F-CE0D + +cartridge sha256:edf990e502c646a2fe83fcd1d359ca0ed5003ace06cb4c3de5a51a0c56d6ec54 + title:R.P.M. Racing (USA) + cheat + description:Sturdy tires are free + code:DDB8-0465 + cheat + description:4-liter high output engine is free + code:DDB1-0F65 + cheat + description:Sell sturdy tires for $4,910 instead of $10 + code:0BBA-0FA5 + cheat + description:Sell 4-liter high output engine for $9,925 instead of $25 + code:BBB5-0DA5 + cheat + description:Start new game with $9,910 instead of $4,910 + code:BBCB-DF61 + cheat + description:Start new game with $49,104,910 + code:62CB-D701 + cheat + description:Start new game with $99,109,910 + code:BBCB-DF61+62CB-D701 + +cartridge sha256:dd0feb78e2d5d81f59241baf3bca5e2edaebbe98f0ac860a4eb6d448718f1ca5 + title:Race Drivin' (USA) + cheat + description:Infinite time + code:A266-07AD + cheat + description:Slow timer + code:8066-04DD + cheat + description:Fast timer + code:4266-04DD + cheat + description:Freeze lap timer + code:2B6C-07AD + cheat + description:Slow lap timer + code:1968-0DAD + +cartridge sha256:1869c0faf93bf21b7ff965f1925fad4b2924a64b1e48f4837221eebdf741226c + title:Radical Rex (USA) + cheat + description:Infinite health + code:89B4-C4D1 + cheat + description:Infinite roar + code:C28C-1FD5+C2C9-D7A4 + cheat + description:Infinite lives + code:C221-3D94 + cheat + description:Don't loose breath level when you die + code:C2B2-4D04+C2BA-4F04 + +cartridge sha256:5fd7666e509f9d3cf1fd6b209dc22f2f3848f74eae7b83239d1090e031fc6df2 + title:Raiden Trad (USA) + cheat + description:Invincibility - both players + code:DDEF-0F1B + cheat + description:Infinite bombs - P1 + code:EDE8-67A4+D9EA-6DD4+3CEA-6D04+23EA-6DA4 + cheat + description:Infinite bombs - P2 + code:2DE8-67A4+D9EA-6DD4+3CEA-6D04+23EA-6DA4 + cheat + description:Infinite bombs - both players + code:3CEA-6D64 + cheat + description:Infinite lives - P1 + code:3CBD-DDD7 + cheat + description:Infinite lives - P2 + code:3CB5-0467 + cheat + description:Replacement planes carry 0 bombs - P1 + code:CEB7-DFD7+62B7-DF07 + cheat + description:Replacement planes carry 6 bombs - P1 + code:91B7-DFD7+6BB7-DF07 + cheat + description:Replacement planes carry 9 bombs - P1 + code:8FB7-DFD7+62B7-DF07 + cheat + description:Replacement planes carry 0 bombs - P2 + code:CEBC-0707+62BC-0767 + cheat + description:Replacement planes carry 6 bombs - P2 + code:91BC-0707+6BBC-0767 + cheat + description:Replacement planes carry 9 bombs - P2 + code:8FBC-0707+62BC-0767 + cheat + description:Start with 1 life - both players + code:B6BD-D76F + cheat + description:Start with 7 lives - both players + code:8BBD-D70F+60BD-D76F + cheat + description:Start with 9 lives - both players + code:8FBD-D70F+62BD-D76F + cheat + description:Start with 0 bombs - P1 + code:CEBF-D7AF+62B4-DDDF + cheat + description:Start with 6 bombs - P1 + code:91BF-D7AF+6BB4-DDDF + cheat + description:Start with 9 bombs - P1 + code:8FBF-D7AF+62B4-DDDF + cheat + description:Start with 0 bombs - P2 + code:CEB7-D7DF+62B7-D70F + cheat + description:Start with 6 bombs - P2 + code:91B7-D7DF+6BB7-D70F + cheat + description:Start with 9 bombs - P2 + code:8FB7-D7DF+62B7-D70F + cheat + description:Start with 3 credits + code:D4BF-6F6F + cheat + description:Start with 4 credits + code:D7BF-6F6F + cheat + description:Start with 6 credits + code:D9BF-6F6F + cheat + description:Start with 8 credits + code:D5BF-6F6F + cheat + description:Start with 10 credits + code:DBBF-6F6F + cheat + description:Start with 1 credit + code:DDBF-6F6F + +cartridge sha256:e19f7d8d5c3e4cefeff5889380d8780495e01f0553d13be4182a15a5d4b615bb + title:Rampart (USA) + cheat + description:Infinite continues + code:C284-DD07 + cheat + description:Infinite cannons + code:3C6B-D467 + cheat + description:Start on battlefield 2 + code:CBAA-67DD+DDAA-676D+DFAA-670D + cheat + description:Start on battlefield 3 + code:CBAA-67DD+DDAA-676D+D4AA-670D + cheat + description:Start on battlefield 4 + code:CBAA-67DD+DDAA-676D+D7AA-670D + cheat + description:Start on battlefield 5 + code:CBAA-67DD+DDAA-676D+D0AA-670D + cheat + description:Start on battlefield 6 + code:CBAA-67DD+DDAA-676D+D9AA-670D + cheat + description:Start on battlefield 7 + code:CBAA-67DD+DDAA-676D+D1AA-670D + +cartridge sha256:32d32ef56af83887cdc2c04b3da4be1cd82a473988deaa2e7dd50d38ef79c3a1 + title:Ranma 1-2 - Hard Battle (USA) + cheat + description:Ranma moves faster + code:D7B4-0DA9+EABF-04D9 + cheat + description:Ranma jumps faster + code:E8B7-07D9+D0B7-0769 + cheat + description:Ranma's diagonal jumps are higher + code:E1B7-0769 + cheat + description:Ranma's diagonal kicks are harder + code:F6B7-AD60 + cheat + description:Ranma's dragon blast kills with 1 hit + code:1DB1-D4D9 + cheat + description:Genma moves faster + code:D78F-6DD5+EA8D-DFD5 + cheat + description:Genma's paternal anger (running at enemy) is faster + code:E48C-6DD5 + cheat + description:Genma's verbal punishment is stronger + code:4689-0465 + cheat + description:Genma's verbal punishment kills with 1 hit + code:1D89-0465 + cheat + description:Ryoga moves faster + code:EA81-6760+D7B5-6460 + cheat + description:Ryoga jumps faster + code:EA8B-6D60+D78B-6760 + cheat + description:Ryoga's bandana throw kills with 1 hit + code:1DD8-DD05 + cheat + description:Shampoo moves faster + code:EAC9-D765+D7C1-D465 + cheat + description:Shampoo's dragon sky kick is faster + code:E9CF-0765 + cheat + description:Shampoo's super fury charge goes farther + code:E9CE-D465 + cheat + description:Shampoo's fury charge 1 hit kill + code:1DCB-A4A1 + cheat + description:Shampoo's kick is faster + code:41C5-67D1 + cheat + description:Akane moves faster + code:EA84-D4D1+D787-DFD1 + cheat + description:Akane jumps faster + code:E880-D7D1+D089-6760 + cheat + description:Akane's 2-step whip kick is faster + code:E68E-DFD1 + cheat + description:Akane's 2-step whip kick is stronger + code:418B-6D69 + cheat + description:Akane's 2-step whip kick kills with 1 hit + code:1D8B-6D69 + cheat + description:Akane's dust devil uppercut is faster + code:3E8A-DF61+EE8A-D401 + cheat + description:Gosunkugi moves faster + code:ECC5-64D9+D0C6-6FD9 + cheat + description:Gosunkugi jumps faster + code:E8CB-67D9+D0CC-64D9 + cheat + description:Gosunkugi's straw man throw does more damage + code:40D8-DD05 + cheat + description:Gosunkugi's straw man throw kills with 1 hit + code:1DD8-DD05 + cheat + description:Ukkyo moves faster + code:ECB8-64D1+D0BA-6FD1 + cheat + description:Ukkyo jumps faster + code:E8B2-67D1+D0B3-64D1 + cheat + description:Mousse's flying egg bombs are faster + code:EBC5-0FD0 + cheat + description:Mousse's eagle claw strike - 1 hit kill + code:1DB1-AF65 + cheat + description:Mousse's claw strike is quicker + code:D6C1-0460 + cheat + description:Every move kills every opponent with 1 hit + code:DDD7-8407 + cheat + description:No knock back when opponent is cornered + code:DD6B-D700 + +cartridge sha256:097cbe9720903bc14599158b80e0cc314ef2fe8a585d6d0a8962eb1626031492 + title:Realm (USA) + cheat + description:Infinite ammo + code:C9E4-3DA7 + cheat + description:Hit anywhere (if a platform is missing go back and come back) + code:01CB-1F07+10CB-C407+2DCB-1FD7+82C3-1FA7+FAC3-14D7 + cheat + description:Invincibility + code:7E007D:4F + cheat + description:Invincibility after first hit + code:C928-4DA7+C92D-1DD7 + cheat + description:Almost invincible + enable stage skip (press Start + Select to skip) (enable code before title screen) + code:ED66-C54F + cheat + description:Almost invincible + enable stage skip (press Start + Select to skip) (enable code before title screen) (alt) + code:7E0224:FF + cheat + description:Infinite health + code:C2EB-4F15 + cheat + description:Infinite health (alt) + code:7E132B:06 + cheat + description:Infinite lives + code:C236-1DFE + cheat + description:Infinite lives (alt) + code:7E1334:03 + cheat + description:Infinite ammo (alt) + code:7E00F5:09 + +cartridge sha256:549f2e5b17f685cad25ba71ce7bc6e004e7bfd09e6be12a827af9a9a26556fff + title:Redline F-1 Racer (USA) + cheat + description:Always in 1st place + code:C98E-6FDF + cheat + description:Infinite special fuel + code:3CAA-AF04 + cheat + description:Instant 255 mph speed (best to get into 6th gear before activating this code, then you can go 357 mph) + code:CBC5-D70F+EEC5-D7AF + cheat + description:No speed loss when you get off accelerator button + code:C98C-6F0F + cheat + description:No speed loss on grass + code:C9BD-0F04 + +cartridge sha256:71e7083cfcf32b738f60f5eeffd4f9d1fd9250afbde0c56e22a4b97abac377a1 + title:Ren & Stimpy Show, The - Fire Dogs (USA) + cheat + description:Invincibility + code:7E257E:05 + cheat + description:Infinite health + code:7E00E3:30 + cheat + description:Infinite lives + code:7E0002:09 + cheat + description:Infinite time (disable on bonus stages) + code:7E00F5:3B + cheat + description:Max money + code:7E0004:E7+7E0005:03 + cheat + description:Infinite Dalmation Paint meter + code:7E0055:EE + cheat + description:Infinite Fire Extinguisher meter + code:7E0059:EE + cheat + description:Have Boots + code:7E2584:01 + cheat + description:Have Bucket + code:7E2586:01 + cheat + description:Have Fire Coat + code:7E2590:01 + cheat + description:Have Fire Hat + code:7E258C:01 + cheat + description:Have Fire Hose + code:7E2582:01 + cheat + description:Have Fire Extinguisher + code:7E2590:01 + cheat + description:Have Socks + code:7E258A:01 + cheat + description:Have Trampoline + code:7E2588:01 + cheat + description:Have 99 sacks of Gritty Kitty (On The Job stages) + code:7E2550:63 + cheat + description:Skip to bonus level (On The Job stages) + code:7E07AE:93+7E07AF:20 + +cartridge sha256:ad7dd4efb8836d4009f6c76bd21865d8f5dcf9c3cbd8fa7bb32d686488847120 + title:Ren & Stimpy Show, The - Time Warp (USA) + cheat + description:Infinite health + code:82ED-4DD6 + cheat + description:Infinite lives + code:3CB1-14AC + cheat + description:Don't have to charge special attack + code:CBBE-4468+6DBE-47D8+DDBE-4768+62BE-47A8 + cheat + description:Flash longer after you die + code:EE33-1F62 + cheat + description:Don't flash after you die + code:EE33-1F62 + cheat + description:Health never goes back up + code:82EA-34D6 + cheat + description:1 kitty gritty gives 99 + code:CBEF-440B+17EF-446B+3CEF-47DB+3CEF-470B + cheat + description:Start with 1 lives + code:DD3A-1DA2 + cheat + description:Start with 5 lives + code:D03A-1DA2 + cheat + description:Start with 10 lives + code:DB3A-1DA2 + cheat + description:Have 99 kitty gritty + code:7E0583:63 + +cartridge sha256:ba54d715abf100b94fee801351986fa818e4309730cefbacf9b4fad36e284c1c + title:Ren & Stimpy Show, The - Veediots! (USA) + cheat + description:Infinite health + code:C2CD-0FA0 + cheat + description:Infinite lives + code:C2C5-0460 + cheat + description:Infinite time + code:C2CF-D7A9 + cheat + description:Powdered Toast Shield lasts 85x longer + code:EEE8-6DD6 + cheat + description:"Socks" power-up lasts 200x longer + code:EEEF-D7AB + cheat + description:Stimpy's mouth won't close + code:C2C5-0FD9 + cheat + description:Money is worth 10x more + code:ECBC-6DA5+ECAB-DDA5 + +cartridge sha256:82a9ee11b5640409c67772363f1148517b26127cef13aa2a8ffc2480b487d81f + title:Rendering Ranger R2 (Japan) + cheat + description:Invincibility + code:7E06AE:03 + cheat + description:Infinite health + code:7E06BC:05 + cheat + description:Infinite lives + code:7E0515:09 + cheat + description:Infinite Bombs + code:7E06C1:03 + cheat + description:Deactivate shield + code:7E06B8:00 + cheat + description:Have Pods (ship stages) + code:7E06B5:01 + cheat + description:Have Blue weapon (press A to switch weapons) + code:7E0AA2:00 + cheat + description:Have Green weapon (press A to switch weapons) + code:7E0AA3:00 + cheat + description:Have Yellow weapon (press A to switch weapons) + code:7E0AA4:00 + cheat + description:Best Red weapon + code:7E0A9D:04 + cheat + description:Best Blue weapon + code:7E0A9E:04 + cheat + description:Best Green weapon + code:7E0A9F:04 + cheat + description:Best Yellow weapon + code:7E0AA0:04 + +cartridge sha256:5fb072c3c2e9d8e7f84bea9c4bf2253e6868eb2b1f13e35a7d75fdf05896d873 + title:Revolution X (USA) + cheat + description:Infinite CDs - both players + code:CBA0-4DDD + cheat + description:Infinite health - P1 + code:7E022B:FF + cheat + description:Infinite CDs - P1 + code:7E0088:FF + +cartridge sha256:f44482e2cccd9fcfd5875d84ff700f6e783f3bd8abd1ac4d939074cd6ad3fe65 + title:Rex Ronan - Experimental Surgeon (USA) (En,Es) + cheat + description:Infinite health + code:7E03C4:FF + +cartridge sha256:38be8013bbe07b2020ba30031fb0a2c77bad8a3eb61fac8217adfe82d6c402af + title:Rise of the Robots (USA) + cheat + description:Infinite time + code:DDAC-5767 + cheat + description:No jumping allowed + code:CBA2-E4D4+DDA2-E404 + cheat + description:Win one round to advance + code:DF78-57AF + cheat + description:Everyone kills with one hit + code:CB34-570F + cheat + description:Every hit does more damage + code:4D34-576F+3CC7-E4A7+DD34-57AF + +cartridge sha256:3f59cc687d22cd1b23cc33ae6e4518234c9da813c01f79f4c43716e12d32a12d + title:Rival Turf! (USA) + cheat + description:Invincibility + code:C2BF-D0EB + cheat + description:Infinite health + code:C965-DDDC + cheat + description:Infinite lives + code:C96C-0DAC + cheat + description:Full health from all food + code:DD6A-AD61 + cheat + description:No score lost when special attack is used + code:DD62-A7A6 + cheat + description:Infinite continues + code:C2C3-0F0D + cheat + description:Start with more health + code:EEC4-OD6F+EE64-646C+EE63-04A7+EE68-A7A1 + cheat + description:Start with less health + code:FEC4-0D6F+FE64-646C+FE63-04A7+FE68-A7A1 + cheat + description:Start with 1 life + code:DDB7-D4A7 + cheat + description:Start with 8 lives + code:D5B7-D4A7 + cheat + description:Start with 9 continues + code:DBB0-DF07 + cheat + description:Start with 1 continue + code:DFB0-DF07 + cheat + description:Invincibility - P1 + code:7E0208:FF + cheat + description:Invincibility - P2 + code:7E02D8:FF + cheat + description:Infinite health - P1 + code:7E0217:FF + cheat + description:Infinite health - P2 + code:7E02E7:FF + cheat + description:Infinite lives - P1 + code:7E023F:09 + cheat + description:Infinite lives - P2 + code:7E030F:09 + cheat + description:Infinite continues (alt) + code:7E10F5:05 + cheat + description:Always angry - P1 + code:7E024F:03 + cheat + description:Always angry - P2 + code:7E031F:03 + cheat + description:One hit kills + code:7E0487:00+7E0557:00+7E024F:00+7E03B7:00 + cheat + description:Infinite points - P1 + code:7E0224:70 + cheat + description:Infinite points - P2 + code:7E02F4:70 + cheat + description:Start on stage 2 - L.A. City Stadium + code:7E0120:01 + cheat + description:Start on stage 3 - Things Are Looking Up + code:7E0120:02 + cheat + description:Start on stage 4 - South Of The Border + code:7E0120:03 + cheat + description:Start on stage 5 - Dockyard Brawl + code:7E0120:04 + cheat + description:Start on stage 6 - Fight to the Finish + code:7E0120:05 + cheat + description:Start on stage - Welcome To The Warp Room + code:7E0120:06 + +cartridge sha256:864aa9068fb23cd20022a9ac36fb9082299278ea0cb07a20deec2b6a1c6cbc70 + title:Road Riot 4WD (USA) + cheat + description:Races are 1 lap instead of 3 + code:DDBF-07DF + cheat + description:Races are 2 laps instead of 3 + code:DFBF-07DF + cheat + description:Races are 4 laps instead of 3 + code:D7BF-07DF + cheat + description:Races are 5 laps instead of 3 + code:D0BF-07DF + cheat + description:Races are 6 laps instead of 3 + code:D9BF-07DF + cheat + description:Races are 7 laps instead of 3 + code:D1BF-07DF + cheat + description:Beginner track has an extra lap + code:3CB4-0DAF + +cartridge sha256:2e8203e421f97cf165f03a5d4f69dadf0bcca18c42c6a1dfe79c8705c522cc54 + title:Road Runner's Death Valley Rally (USA) + cheat + description:Protection against most hazards + code:C2AC-346F+C2C3-1D28 + cheat + description:Infinite lives + code:DDB2-4D64 + cheat + description:Infinite time + code:DDBB-4467 + cheat + description:Stay invincible longer after getting hit (Road Runner blinks) + code:EE8C-C4DD + cheat + description:Stay invincible for less time after getting hit (Road Runner blinks) + code:0D8C-C4DD + cheat + description:Stay invincible after getting hit until you fall and die (Road Runner blinks) + code:C2C5-C7AF + cheat + description:Stay invincible after getting hit until you fall and die (Road Runner does not blink) + code:6DC5-C70F + cheat + description:Eating birdseed restores turbo speed meter to maximum + code:7D26-3404 + cheat + description:Eating birdseed does nothing + code:DD26-3404 + cheat + description:Using turbo speed does not use up bird seed + code:DDC6-3D67 + cheat + description:Hearts worth nothing + code:C229-C707 + cheat + description:1-up worth nothing + code:DD33-4DDD + cheat + description:1-up worth 2 + code:D433-4DDD + cheat + description:1-up worth 3 + code:D733-4DDD + cheat + description:1-up worth 4 + code:D033-4DDD + cheat + description:1-up worth 5 + code:D933-4DDD + cheat + description:Bogus jump + code:7D83-47DD + cheat + description:Better jump + code:FD83-47DD + cheat + description:Super-jump + code:DC83-47DD + cheat + description:Mega-jump + code:D983-47DD + cheat + description:Start with more birdseed on the turbo speed meter + code:7DBD-44D7 + cheat + description:Start with less birdseed on the turbo speed meter + code:FDBD-44D7 + cheat + description:Start timer at 3:00 instead of 5:00 + code:D7B0-346F + cheat + description:Start timer at 7:00 + code:D5B0-346F + cheat + description:Start timer at 9:00 + code:DBB0-346F + cheat + description:Start with 2 lives + code:DFBC-3FD4 + cheat + description:Start with 4 lives + code:D7BC-3FD4 + cheat + description:Start with 6 lives + code:D9BC-3FD4 + cheat + description:Start with 8 lives + code:D5BC-3FD4 + cheat + description:Start with 10 lives + code:DBBC-3FD4 + cheat + description:Start with 21 lives + code:4DBC-3FD4 + cheat + description:Start with 51 lives + code:9DBC-3FD4 + cheat + description:Start with 76 lives + code:59BC-3FD4 + cheat + description:Start with 100 lives + code:BBBC-3FD4 + cheat + description:Start on level 1, sub-level 2 + code:F3BB-3FA4+3FBB-3F64+DFBB-3FD4 + cheat + description:Start on level 1, sub-level 3 + code:F3BB-3FA4+3FBB-3F64+D4BB-3FD4 + cheat + description:Start on level 1, sub-level 4 + code:F3BB-3FA4+3FBB-3F64+D7BB-3FD4 + cheat + description:Start on level 2, sub-level 1 + code:F3BB-3FA4+3FBB-3F64+D0BB-3FD4 + cheat + description:Start on level 2, sub-level 2 + code:F3BB-3FA4+3FBB-3F64+D9BB-3FD4 + cheat + description:Start on level 2, sub-level 3 + code:F3BB-3FA4+3FBB-3F64+D1BB-3FD4 + cheat + description:Start on level 2, sub-level 4 + code:F3BB-3FA4+3FBB-3F64+D5BB-3FD4 + cheat + description:Start on level 3, sub-level 1 + code:F3BB-3FA4+3FBB-3F64+D6BB-3FD4 + cheat + description:Start on level 3, sub-level 2 + code:F3BB-3FA4+3FBB-3F64+DBBB-3FD4 + cheat + description:Start on level 3, sub-level 3 + code:F3BB-3FA4+3FBB-3F64+DCBB-3FD4 + cheat + description:Start on level 3, sub-level 4 + code:F3BB-3FA4+3FBB-3F64+D8BB-3FD4 + cheat + description:Start on level 4, sub-level 1 + code:F3BB-3FA4+3FBB-3F64+DABB-3FD4 + cheat + description:Start on level 4, sub-level 2 + code:F3BB-3FA4+3FBB-3F64+D2BB-3FD4 + cheat + description:Start on level 4, sub-level 3 + code:F3BB-3FA4+3FBB-3F64+D3BB-3FD4 + cheat + description:Start on level 4, sub-level 4 + code:F3BB-3FA4+3FBB-3F64+DEBB-3FD4 + cheat + description:Start on level 5, sub-level 1 + code:F3BB-3FA4+3FBB-3F64+FDBB-3FD4 + cheat + description:Start on level 5, sub-level 2 + code:F3BB-3FA4+3FBB-3F64+FFBB-3FD4 + cheat + description:Start on level 5, sub-level 3 + code:F3BB-3FA4+3FBB-3F64+F4BB-3FD4 + cheat + description:Start on level 5, sub-level 4 + code:F3BB-3FA4+3FBB-3F64+F7BB-3FD4 + +cartridge sha256:a2115e7576dec06e0de613efb89de861815a78ef72e78a3784be09fb7541928f + title:RoboCop versus The Terminator (USA) + cheat + description:Infinite lives + code:DDBE-0D05 + cheat + description:Super-jump + code:DD37-C4D7 + cheat + description:Rockets do more damage + code:DE63-C460 + cheat + description:Normal pistol does more damage + code:DE60-4460 + cheat + description:Plasma Rifle does massive damage + code:7D66-1F00 + cheat + description:Only 10 Terminators to kill on the 3-D Stage + code:FD64-446F + cheat + description:Only 30 Terminators to kill on the 3-D Stage + code:7D64-446F + cheat + description:Start with 1 life + code:DFB3-CD0D + cheat + description:Start with 9 lives + code:DBB3-CD0D + cheat + description:Start with 15 lives (ignore counter) + code:DEB3-CD0D + cheat + description:Infinite health + code:7E10C5:0A + cheat + description:Infinite lives (alt) + code:019DF1:00 + cheat + description:Super-jump (alt) + code:80EE38:00 + cheat + description:Normal pistol does more damage (alt) + code:81804A:0F + +cartridge sha256:055d9c6311a663af7c899a6f76a419c274c57baada3ef64c52fadb1c676b1446 + title:RoboCop 3 (USA) + cheat + description:Infinite lives + code:4A6E-6FDD + cheat + description:Slower timer + code:5D69-6D0F + cheat + description:Faster timer + code:FE69-6D0F + cheat + description:Infinite ammo (except flame thrower) + code:DDC7-A7A4 + cheat + description:Ammo pick-ups worth more + code:DFEC-DD67+D4EC-DFD7 + cheat + description:Ammo pick-ups worth less + code:7DEC-DD07+DDEC-DFD7+7DEC-DDA7 + cheat + description:Faster Robocop - except on stages 3 and 5 + code:D4C7-64DD+E3C9-6DAD + cheat + description:Start with 1 life + code:DD62-D7DD + cheat + description:Start with 6 lives + code:D962-D7DD + cheat + description:Start on stage 2 + code:DF37-64A4 + cheat + description:Start on stage 3 + code:D437-64A4 + cheat + description:Start on stage 4 + code:D737-64A4 + cheat + description:Start on stage 5 + code:D037-64A4 + cheat + description:Infinite health + code:7E0477:38 + cheat + description:Infinite lives (alt) + code:7E1854:05 + cheat + description:Infinite ammo + code:7E1848:99 + cheat + description:Infinite time + code:7E030C:12+7E030D:04 + cheat + description:Have all weapons + code:7E046F:04 + +cartridge sha256:1e2ded7b1e350449b7a99b7ec414525e4b9b086c416deeee5eb3e48e032c46bd + title:Robotrek (USA) + cheat + description:Infinite battle bonus time + code:3CAA-3DFF + cheat + description:Infinite robot points + code:6DCE-3D43 + cheat + description:Infinite vanish time + code:C234-3F3E + cheat + description:Everything is free + code:C23C-CDC7 + cheat + description:Get 9900 gold when you look into the robot book + code:BBB9-4D7D + cheat + description:More energy for robot energy + code:BDE6-1DC2 + cheat + description:Mean robot + code:CBEB-1FB9+BBEB-1F29+DDEB-14F9+3CEB-1499 + cheat + description:One-hit kills + code:CBE2-C74A + cheat + description:Start at level 3 + code:CB34-3D47+D734-3D17 + cheat + description:Start at level 10 + code:CB34-3D47+DC34-3D17 + cheat + description:Start at level 20 + code:CB34-3D47+F034-3D17 + cheat + description:Start at level 50 + code:CB34-3D47+7434-3D17 + cheat + description:Start at level 50 (alt) + code:88EF20:A9+88EF21:32 + cheat + description:Infinite GP + code:7E06E6:99+7E06E7:99+7E06E8:09 + cheat + description:Max Program Points + code:7E0688:73+7E0689:05 + cheat + description:Max HP - First Robot + code:7E068A:FF + +cartridge sha256:9d721753301278325c851f1843d669a697aed757dcf6495a31fc31ddf664b182 + title:Rock n' Roll Racing (USA) + cheat + description:Infinite forward weapons + code:C2BF-476F + cheat + description:Infinite power charges + code:C2BF-1FA4 + cheat + description:No damage from hitting other cars + code:3CE5-CD67 + cheat + description:No damage from most mines + code:DD26-34D7 + cheat + description:No points needed to advance to any level + code:BACB-C465 + cheat + description:Buy items for free if you have enough money + code:C28C-CF69+C28B-C4A9 + cheat + description:More damage from mines + code:D126-34D7 + cheat + description:Red Cross packages worth nothing + code:DD36-4F0D + cheat + description:Red Cross packages can blow up + code:FD36-4F0D + cheat + description:Start with $50,000 + code:D9CF-CDD5 + cheat + description:Start with $100,000 + code:FDCF-CDD5 + cheat + description:Start with $500,000 + code:9DCF-CDD5 + cheat + description:Start with $990,000 + code:BBCF-CDD5 + cheat + description:Start with $5,020,000 + code:D9CF-CD05 + +cartridge sha256:b072fd9b08042e3262446fdf418a41848251072a32bd7f8335cc03543c4ae6c8 + title:Rocketeer, The (USA) + cheat + description:Protection against guns (only partly against grenades) (only in hangar) + code:C988-0FAD + cheat + description:Protection against Armored Flying Tank + code:C98C-DD0F + cheat + description:Protection against enemy rocketmen on the Zeppelin + code:C9A0-A40F + cheat + description:Invincibility in the skies + code:C964-6FDD + cheat + description:Infinite Super Shots on pick-up + code:C961-A767 + cheat + description:Infinite chances + code:8260-0FA7 + cheat + description:Automatically win first race at Bigelow + code:DD62-67AF + cheat + description:Automatically win second race at Bigelow + code:DD63-6DDF + cheat + description:Automatically win third race at Bigelow + code:DD63-6D0F + cheat + description:First race at Bigelow is 1 lap instead of 10 + code:DF62-67AF + cheat + description:First race at Bigelow is 5 laps + code:D962-67AF + cheat + description:First race at Bigelow is 15 laps + code:DE62-67AF + cheat + description:First race at Bigelow is 25 laps + code:FB62-67AF + cheat + description:First race at Bigelow is 50 laps + code:7462-67AF + cheat + description:First race at Bigelow is 99 laps + code:1762-67AF + cheat + description:Second race at Bigelow is 1 lap + code:DF63-6DDF + cheat + description:Second race at Bigelow is 5 laps + code:D963-6DDF + cheat + description:Second race at Bigelow is 10 laps + code:DC63-6DDF + cheat + description:Second race at Bigelow is 25 laps + code:FB63-6DDF + cheat + description:Second race at Bigelow is 50 laps + code:7463-6DDF + cheat + description:Second race at Bigelow is 99 laps + code:1763-6DDF + cheat + description:Third race at Bigelow is 1 lap instead of 10 + code:DF63-6D0F + cheat + description:Third race at Bigelow is 5 laps + code:D963-6D0F + cheat + description:Third race at Bigelow is 25 laps + code:FB63-6D0F + cheat + description:Third race at Bigelow is 50 laps + code:7463-6D0F + cheat + description:Third race at Bigelow is 99 laps + code:1763-6D0F + cheat + description:Cliff starts with 2/3 normal energy in hangar + code:0C6D-A4DF + cheat + description:Cliff starts with 1/3 normal energy in hangar + code:496D-A4DF + cheat + description:Enemies start with 2/3 normal energy in hangar + code:0C6D-A7AF + cheat + description:Enemies start with 1/3 normal energy in hangar + code:496D-A7AF + cheat + description:Super Shots worth nothing on pick-up instead of 3 + code:DD6B-D76F + cheat + description:Super Shots worth 6 on pick-up (cannot gain over 29) + code:D16B-D76F + cheat + description:Super Shots worth 9 on pick-up (cannot gain over 29) + code:DB6B-D76F + cheat + description:Super Shots worth 12 on pick-up (cannot gain over 29) + code:DA6B-D76F + cheat + description:Easily defeat enemy rocketmen on the Zeppelin + code:10A8-DFDF + cheat + description:Start with 1 chance instead of 3 + code:DF6C-07AF + cheat + description:Start with 2 chances + code:D46C-07AF + cheat + description:Start with 4 chances + code:D06C-07AF + cheat + description:Start with 5 chances + code:D96C-07AF + cheat + description:Start with 6 chances + code:D16C-07AF + cheat + description:Start with 7 chances + code:D56C-07AF + cheat + description:Start with 8 chances + code:D66C-07AF + cheat + description:Start with 9 chances + code:DB6C-07AF + +cartridge sha256:4fc2832e7aa01d105ca67977b38840ec1188869b5e74d20e58613c1cd127d78f + title:Rockman & Forte (Japan) + cheat + description:Invincibility against enemies + code:1808-5FA2 + cheat + description:Invincibility against fire + code:187F-7D09 + cheat + description:Invincibility against pits + code:1D48-74D5 + cheat + description:Invincibility against spikes + code:1873-E400 + cheat + description:One hit kills + code:4006-5F02 + cheat + description:Multi-jump - Megaman + code:1DFB-7F05+5EFB-7F65+4D51-EDD5+E251-ED05+7C51-ED65+4D51-EDA5+3B51-EFD5+7F51-EF05+1D51-EF65 + cheat + description:Multi-jump - Bass + code:E241-8D69 + cheat + description:Invincibility + code:7E0C30:30 + cheat + description:Infinite health + code:7E0C2F:1C + cheat + description:Infinite sliding time + code:7E0C54:01 + cheat + description:Infinite Beat + code:7E0B94:9C + cheat + description:Infinite Eddie + code:7E0B96:9C + cheat + description:Infinite Bolts + code:7E0B9C:E7+7E0B9D:03 + cheat + description:Infinite Mines + code:7E0B86:9F + cheat + description:Infinite T. Blade + code:7E0B8E:9F + cheat + description:Infinite Ice Wall + code:7E0B8C:9F + cheat + description:Infinite W. Burner + code:7E0B88:9F + cheat + description:Infinite S. Drill + code:7E0B82:9F + cheat + description:Infinite L. Bolt + code:7E0B84:9F + cheat + description:Infinite C. Vision + code:7E0B90:9F + cheat + description:Infinite M. Cards + code:7E0B8A:9F + cheat + description:Infinite Gospel Booster/Rush Search + code:7E0B92:9F + cheat + description:Have all items + code:7E0B97:FF+7E0B98:FF+7E0B99:FF + cheat + description:Have CD Sparkle info + code:7E0B98:FF + cheat + description:Have first 5 Units + code:7E0B97:FF + cheat + description:Have all CDs + code:306045:FF+306046:FF+306047:FF+306048:FF+306049:FF+30604A:FF+30604B:FF+30604C:1F+306040:FE+306041:FF+306042:FF+306043:FF+306044:FF + cheat + description:One hit kills (alt) + code:7E1A2F:01 + cheat + description:Last area open + code:7E0B79:FF + cheat + description:Last area, last level + code:7E0B7B:03 + +cartridge sha256:7c0f915b581796e5b6dd384ecdc0dad8af4d956492fbcedec628c8845d911d7e + title:Rocky Rodent (USA) + cheat + description:Infinite lives + code:3CAD-4DA7 + cheat + description:Keep hairdo after you die + code:C2C3-3DD5 + cheat + description:Start with red hairdo + code:D4A8-17D4 + cheat + description:Start with purple hairdo + code:D0A8-17D4 + cheat + description:Start with corkscrew hairdo + code:D1A8-17D4 + cheat + description:Start with green ponytail hairdo + code:D6A8-17D4 + cheat + description:Start with birdnest hairdo + code:DCA8-17D4 + cheat + description:Invincibility + code:7E0054:72 + +cartridge sha256:f7e3c3012af2dbad350646b6ef3470f0b4c42e4a2873109f7aa6c81d7157c887 + title:Roger Clemens' MVP Baseball (USA) (Rev 1) + cheat + description:Batter never walks + code:C22D-6FAD + cheat + description:Batter never strikes out + code:C227-6D6D + cheat + description:1 ball per walk + code:DF2D-676D + cheat + description:2 balls per walk + code:D42D-676D + cheat + description:3 balls per walk + code:D72D-676D + cheat + description:5 balls per walk + code:D92D-676D + cheat + description:6 balls per walk + code:D12D-676D + cheat + description:7 balls per walk + code:D52D-676D + cheat + description:1 strike per out + code:DF27-640D + cheat + description:2 strikes per out + code:D427-640D + cheat + description:4 strikes per out + code:D027-640D + cheat + description:5 strikes per out + code:D927-640D + cheat + description:Each run counts as 2 + code:7665-0FD1+7669-0F01 + cheat + description:1 out per inning per team + code:DFBF-07DF + cheat + description:2 outs per inning per team + code:D4BF-07DF + +cartridge sha256:815bfcf4fd6eb23a20c2e50dde023c210b273ffb6cd86a93909d803c3643ce46 + title:Romance of the Three Kingdoms II (USA) + cheat + description:Scenario 1 - Start with 30,000 gold pieces + code:7DE7-A465+59E7-A4A5 + cheat + description:Scenario 1 - Start with 30,000 rice + code:7DE7-A765+59E7-A705 + cheat + description:Scenario 1 - Start with 30,000 population + code:7DE7-A765+59E7-A7A5 + cheat + description:Scenario 2 - Start with 30,000 gold pieces + code:7D67-A406+596D-A466 + cheat + description:Scenario 2 - Start with 30,000 rice + code:7D67-A4A6+596D-A7D6 + cheat + description:Scenario 2 - Start with 30,000 population + code:7D67-A706+596D-A766 + cheat + description:Scenario 3 - Start with 30,000 gold pieces + code:7D67-A7DB+5967-A70B + cheat + description:Scenario 3 - Start with 30,000 rice + code:7D67-A76B+5967-A7AB + cheat + description:Scenario 3 - Start with 30,000 population + code:7D60-ADDB+5960-AD0B + cheat + description:Scenario 4 - Start with 30,000 gold pieces + code:7D67-A70C+5967-A76C + cheat + description:Scenario 4 - Start with 30,000 rice + code:7D67-A7AC+5960-ADDC + cheat + description:Scenario 4 - Start with 30,000 population + code:7D60-AD0C+5960-AD6C + cheat + description:Scenario 5 - Start with 30,000 gold pieces + code:7DBB-D7D6+59BB-D706 + cheat + description:Scenario 5 - Start with 30,000 rice + code:7DBB-D766+59BB-D7A6 + cheat + description:Scenario 5 - Start with 30,000 population + code:7DBC-DDD6+59BC-DD06 + cheat + description:Scenario 6 - Start with 30,000 gold pieces + code:7DB9-6766+59B9-67A6 + cheat + description:Scenario 6 - Start with 30,000 rice + code:7DB1-6DD6+59B1-6D06 + cheat + description:Scenario 6 - Start with 30,000 population + code:7DB1-6D66+59B1-6DA6 + +cartridge sha256:4158e3e8890a52f0b12dc9ad5a29276058a247ff41e9f1d22897ebde1eb11269 + title:Run Saber (USA) + cheat + description:Almost invincible - P1 (disable if you fall into a pit) + code:C2B9-CDA4 + cheat + description:Almost invincible - P2 (disable if you fall into a pit) + code:C2B1-C4A4 + cheat + description:Almost invincible - both players (disable if you fall into a pit) + code:18B0-C4A4 + cheat + description:Infinite lives - P1 + code:DD21-1F6F + cheat + description:Infinite lives - P2 + code:DD26-1F6F + cheat + description:Infinite Super Bombs - P1 + code:DDE4-39E3 + cheat + description:Infinite Super Bombs - P2 + code:DDEF-3073 + cheat + description:Infinite continues + code:C2E7-4572 + cheat + description:Level select and 9 lives selectable on the option menu + code:DF3A-6454 + cheat + description:Bomb power-ups give no Super Bombs + code:DDE1-44B5 + cheat + description:Bomb power-ups give 2 Super Bombs + code:D4E1-44B5 + cheat + description:Start with no Super Bombs + code:DD29-0474 + cheat + description:Start with 1 Super Bomb + code:DF29-0474 + cheat + description:Start with 5 Super Bombs + code:D929-0474 + cheat + description:Start with 9 Super Bombs + code:DB29-0474 + cheat + description:Start with 1 health + code:DF25-0D84 + cheat + description:Start with 4 health + code:D025-0D84+D039-0454 + cheat + description:Start with 5 health + code:D925-0D84+D939-0454 + cheat + description:Start with 8 health + code:D625-0D84+D639-0454 + cheat + description:Start with no continues + code:DF83-AD84 + cheat + description:Start with 1 continue + code:D483-AD84 + cheat + description:Start with 5 continues + code:D183-AD84 + cheat + description:Start with 9 continues + code:DC83-AD84 + +cartridge sha256:00e78318926e5cae79bce0535fddd3dccaa732f5c70e43acefc2769a9899eaed + title:Rushing Beat Shura (Japan) + cheat + description:Invincibility + code:C22A-1DD7 + cheat + description:One hit kills + code:1028-CDD3 + +cartridge sha256:0aa16d6b588ba05ab00936201e68a694746fc5e1b2e4f2dbf7cda09265a81379 + title:Sailormoon (France) + cheat + description:Infinite HP - P2 + code:7E07C0:50 + cheat + description:Infinite Bombs + code:7E0759:09 + cheat + description:Full charge meter + code:7E0756:20 + +cartridge sha256:5db804171fca42486485ed85e4afe45b29e6d01304bdf75d520bfc42429739e3 + title:Samurai Shodown (USA) + cheat + description:Max POW meter after one hit + code:DFE1-876D + cheat + description:Start with 1/2 health + code:0D94-7401 + cheat + description:Start with 1/4 health + code:4D94-7401 + cheat + description:Start with 33 seconds + code:4F53-74A4 + cheat + description:Infinite health - P1 + code:7E6214:80 + cheat + description:Infinite health - P2 + code:7E6614:80 + cheat + description:Infinite time + code:7EBE9B:63 + cheat + description:Max POW meter - P1 + code:7E623D:20 + cheat + description:Max POW meter - P2 + code:7E663D:20 + cheat + description:One hit kills - P1 + code:7E6614:01 + cheat + description:One hit kills - P2 + code:7E6214:01 + +cartridge sha256:c894d0d3b99ebbc54910c1d65ceae4272c959c8693a87c58e040bc5a5f74f129 + title:Sanrio World Smash Ball! (Japan) + cheat + description:Always have Strong Smash - P1 + code:7E0070:A0 + cheat + description:Always have Strong Smash - P2 + code:7E0086:A0 + cheat + description:Never have Strong Smash - P1 + code:7E0070:00 + cheat + description:Never have Strong Smash - P2 + code:7E0086:00 + +cartridge sha256:34e1af0642c85148c5a3dc3c7ab4bcbda13a9fea190934b5526c555fff035651 + title:Saturday Night Slam Masters (USA) + cheat + description:Able to pick the same characters + code:1D79-EFD4+1D77-E404 + cheat + description:Stingray becomes Biff + code:DDC1-CF6F + cheat + description:Stingray becomes Gunloc + code:DFC1-CF6F + cheat + description:Stingray becomes Oni + code:D4C1-CF6F + cheat + description:Stingray becomes Titan + code:D7C1-CF6F + cheat + description:Stingray becomes Haggar + code:D9C1-CF6F + cheat + description:Stingray becomes Grater + code:D1C1-CF6F + cheat + description:Stingray becomes Rasta + code:D5C1-CF6F + cheat + description:Stingray becomes Jumbo + code:D6C1-CF6F + cheat + description:Stingray becomes Scorpion + code:DBC1-CF6F + cheat + description:Biff becomes Gunloc + code:DFC1-CD6F + cheat + description:Biff becomes Oni + code:D4C1-CD6F + cheat + description:Biff becomes Titan + code:D7C1-CD6F + cheat + description:Biff becomes Stingray + code:D0C1-CD6F + cheat + description:Biff becomes Haggar + code:D9C1-CD6F + cheat + description:Biff becomes Grater + code:D1C1-CD6F + cheat + description:Biff becomes Rasta + code:D5C1-CD6F + cheat + description:Biff becomes Jumbo + code:D6C1-CD6F + cheat + description:Biff becomes Scorpion + code:DBC1-CD6F + cheat + description:14-second count outside ring + code:D3DB-5D01 + cheat + description:10-second count outside ring + code:DCDB-5D01 + cheat + description:9-second count for pin + code:DBD6-5DD1 + cheat + description:6-second count for pin + code:D1D6-5DD1 + cheat + description:1-second count for pin + code:DFD6-5DD1 + cheat + description:Faster timer + code:F31F-8F0D + cheat + description:Slower timer + code:1D1F-8F0D + cheat + description:Stingray has faster jalepeno comet + code:D12D-5765+EB2F-5F05 + cheat + description:Quicker 'pattycake slap' for Grater + code:0C83-17D7+D78E-1F67 + cheat + description:Quicker 'sonic fist' for Gunloc + code:0C83-1FA7+D78E-1D07 + cheat + description:Quicker 'sonic fist' for Biff + code:0C83-1F67+D78E-1D07 + cheat + description:Quicker 'jungle fever' for Rasta + code:0C83-1707+D48E-1FA7 + cheat + description:Infinite time + code:7E1A70:01 + +cartridge sha256:7fb5236d10852125f0f37c2188b907d636647400a57bccbdb2f63098ffae8b2d + title:Scooby-Doo Mystery (USA) + cheat + description:Infinite health + code:DDED-3F01 + cheat + description:Infinite lives + code:C2BF-3DAD + cheat + description:Most enemies are more frightening + code:EEED-3F01 + cheat + description:Scooby snacks do nothing + code:C26D-1FD5 + cheat + description:Scooby snacks reduce more fright + code:EE64-1DD5 + cheat + description:Start with 1 life + code:DD60-1467 + cheat + description:Start with 5 lives + code:D060-1467 + cheat + description:Start with 7 lives + code:D160-1467 + cheat + description:Start with 10 lives + code:DB60-1467 + +cartridge sha256:39c69dfbba31086cee0c6a034186148c46e1e6c86fcb8e990fb5364a8845fbcd + title:SD Kidou Senshi Gundam - V Sakusen Shidou (Japan) + cheat + description:Invincibility + code:1D68-6FA0+1D6F-A7D0 + +cartridge sha256:8cd9eea0f01e2442727e4624199afaa42dceeb05b9084a4358cadbe4e5a04577 + title:SD The Great Battle - Aratanaru Chousen (Japan) + cheat + description:Invincibility + code:1DC5-A7D7+C9C1-0FD4 + cheat + description:Infinite lives + code:C968-67AF + +cartridge sha256:a4ab8cfad2f236675b1c0124f8484688e149f38e8628a3b38e9ec14d491ec07e + title:SeaQuest DSV (USA) + cheat + description:Infinite weapons / items + code:8ECC-3F9D+8EC8-44FF + cheat + description:Start with 99 Darwin's Aqua Lungs + code:17EC-C400 + cheat + description:Start with 99 HR Probes + code:17E8-CD00 + cheat + description:Start with 99 Sea Trucks + code:17EC-C7A0 + cheat + description:Start with 99 Sea Speeders + code:17EC-C4A0 + cheat + description:Start with 99 Crabs + code:17EC-CFA0 + cheat + description:Start with 99 Stingers + code:17EC-C700 + +cartridge sha256:17c864a76d498feb6479eee8e7d6807b951c66225033228622bb66754baab1db + title:Secret of Evermore (USA) + cheat + description:Everyone is invincible, including enemies + code:C2A0-CD5A+826B-41DF+D261-400F + cheat + description:Infinite Alchemy ingredients + code:8EA4-C905+8EAE-11D5 + cheat + description:Alchemy levels up on every use + code:DDA9-15D5 + cheat + description:View Boy's stats to get 131,074 Talons (don't use if you already have more than that) + code:CBC4-3DE0+D4C4-3F70+DDC4-3F50+62C4-3470 + cheat + description:Your dog starts with 99 HP + code:17BF-1FEF + cheat + description:Your dog starts with 255 HP + code:EEBF-1FEF + cheat + description:Start with 99 attack points + code:95B9-34ED + cheat + description:Start with a lot of attack points + code:EEB9-34ED + cheat + description:Start with 99 defense points + code:17B5-C75D + cheat + description:Start with a lot of defense points + code:EEB5-C75D + cheat + description:Start with 99 magic defense points + code:17B7-445F + cheat + description:Start with a lot of magic defense points + code:EEB7-445F + cheat + description:Start with 50 evade % points + code:7464-CFE7 + cheat + description:Start with 99 evade % points + code:1764-CFE7 + cheat + description:Start with 50 hit % points + code:746D-3F57 + cheat + description:Start with 99 hit % points + code:176D-3F57 + cheat + description:Start with 99 HP + code:1786-CFEB+17BB-17ED + cheat + description:Start with 255 HP + code:EE86-CFEB+EEBB-17ED + cheat + description:Have all weapons + code:7E22DA:FF+7E22DB:FF + +cartridge sha256:4c15013131351e694e05f22e38bb1b3e4031dedac77ec75abecebe8520d82d5f + title:Secret of Mana (USA) + cheat + description:Protection from most hits (disable to kill enemies) + code:8208-776D + cheat + description:Enemies die instantly + code:CD7E-7D67+DD7E-7DA7+DD7E-7FD7 + cheat + description:Hit anywhere + code:40A7-6765+402C-0F60 + cheat + description:Level 99 after first enemy + code:B606-7F6F+DD78-5F64 + cheat + description:Max weapon damage + code:BA0A-5404+CB0A-54D4 + cheat + description:Change screens to max out Strength, Agility, Constitution, Intelligence and Wisdom + code:DD03-ED04 + cheat + description:Weapon bar never decreases + code:82A0-6466+82E0-0FD4 + cheat + description:Walk through walls + code:DD85-A7D1+DD85-64A1 + cheat + description:Strength for level 16 is 90 + code:9C06-81AD + cheat + description:Agility for level 16 is 90 + code:9C06-85DD + cheat + description:Constitution for level 16 is 90 + code:9C06-850D + cheat + description:Intelligence for level 16 is 90 + code:9C06-856D + cheat + description:Wisdom for level 16 is 90 + code:9C06-85AD + cheat + description:Chest in elder's basement in Potos gives you 65360 GP + code:EE6B-8738 + cheat + description:Staying at the inn in Potos is free if you have enough money + code:C274-8764+C277-8DA4 + cheat + description:Items in the shop at Potos are free if you have enough money + code:CE5F-5767 + cheat + description:Candy costs nothing + code:DDEB-E544 + cheat + description:Overalls costs nothing + code:DDE3-E044 + cheat + description:Bandanna costs nothing + code:DDE8-E9C4 + cheat + description:Cup Of Wishes costs nothing + code:DDEC-E9C4 + cheat + description:Medical Herb costs nothing + code:DDEC-E944 + cheat + description:Wristband costs nothing + code:DDE7-7047 + cheat + description:Hair Ribbon costs nothing + code:DDE8-E144 + cheat + description:Rabite Cap costs nothing + code:DDE8-E1C4 + cheat + description:Faerie Walnut costs nothing + code:DDEC-E0C4+DDEC-E034 + cheat + description:Royal Jam costs nothing + code:DDEC-E044 + cheat + description:Chocolate costs nothing + code:DDEB-E5C4 + cheat + description:Staying at Neko's costs nothing instead of 30 + code:DDAB-E715 + cheat + description:Start with 255 GP + code:EE28-EDAF + cheat + description:Start with 32,768 GP + code:6D28-EFDF + cheat + description:Start with 65,280 GP + code:EE28-EFDF + cheat + description:Start at Level 16 + code:6F09-8707 + +cartridge sha256:ab3d724f3032337300c0cc10259447b173793b9dc25f1f250baf785e9c16bb7d + title:Shadow, The (USA) (Proto) (Alt 1) + cheat + description:Infinite health + code:7E1E31:FF + cheat + description:Infinite dash + code:7E1876:FF + cheat + description:Infinite time + code:7E1B76:09 + cheat + description:Enemy 1 has 0 health + code:7E1B4A:00 + cheat + description:Enemy 2 has 0 health + code:7E1B4B:00 + cheat + description:Enemy 3 has 0 health + code:7E1B4C:00 + cheat + description:Start on level 2 - Empire State + code:7E1E28:01 + cheat + description:Start on level 3 - Amusement Park + code:7E1E28:02 + cheat + description:Start on level 4 - The Museum + code:7E1E28:03 + cheat + description:Start on level 5 - The Federal Buildings + code:7E1E28:04 + cheat + description:Start on level 6 - The Bike Chase + code:7E1E28:05 + cheat + description:Start on level 7 - Maritech Labs + code:7E1E28:06 + cheat + description:Start on level 8 - China Town + code:7E1E28:07 + cheat + description:Start on level 9 - Hotel Monolith + code:7E1E28:08 + +cartridge sha256:85092f4c566b4d34bd4bd70be55df92bfbda40f0030e63a15bafbb8f760c1519 + title:Shadow, The (USA) (Proto) + cheat + description:Infinite health + code:7E1E31:FF + cheat + description:Infinite dash + code:7E1876:FF + cheat + description:Infinite time + code:7E1B76:09 + cheat + description:Enemy 1 has 0 health + code:7E1B4A:00 + cheat + description:Enemy 2 has 0 health + code:7E1B4B:00 + cheat + description:Enemy 3 has 0 health + code:7E1B4C:00 + cheat + description:Start on level 2 - Empire State + code:7E1E28:01 + cheat + description:Start on level 3 - Amusement Park + code:7E1E28:02 + cheat + description:Start on level 4 - The Museum + code:7E1E28:03 + cheat + description:Start on level 5 - The Federal Buildings + code:7E1E28:04 + cheat + description:Start on level 6 - The Bike Chase + code:7E1E28:05 + cheat + description:Start on level 7 - Maritech Labs + code:7E1E28:06 + cheat + description:Start on level 8 - China Town + code:7E1E28:07 + cheat + description:Start on level 9 - Hotel Monolith + code:7E1E28:08 + +cartridge sha256:e6bc0a595d5c7c4bc0bbb61ffe35a70288a77eb78544ed74682d489a9e6f07f4 + title:Shadowrun (USA) + cheat + description:Everything is free + code:6DAE-4FA7+FFAE-44D7 + cheat + description:Don't subtract karma for spells/skills (must have enough to advance) + code:CEEF-4DDD + cheat + description:Don't subtract karma for shooting people (ignore message saying you lost karma) + code:CE6D-47A4 + cheat + description:Don't subtract spell points (works for all spell casters) (casting spells you aren't allowed to raises your spell points) + code:8E69-3DA4 + cheat + description:Going up 1 body point adds 20 stamina instead of 10 + code:F0E1-1FDD + cheat + description:Going up 1 body point adds 30 stamina instead of 10 + code:F3E1-1FDD + cheat + description:Add 65,000 nuyen (if less than 65,000) + code:DFBC-17AF+DEB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Add about 131,000 nuyen (if less than 65,000) + code:D4BC-17AF+DEB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Add about 524,000 nuyen (if less than 65,000) + code:D6BC-17AF+DEB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set stamina to 100 + code:10BC-17AF+DDB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set stamina to 200 + code:A6BC-17AF+DDB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set magic total possible to 10 (and spell points to 100) + code:DCBC-17AF+EAB8-1D0F+78B8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set total possible magic to 20 (and spell points to 200) + code:F0BC-17AF+EAB8-1D0F+78B8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set total possible magic to 25 (and spell points to 250) + code:FBBC-17AF+EAB8-1D0F+78B8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set strength to 6 + code:D1BC-17AF+E2B8-1D0F+78B8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set charisma to 6 + code:D1BC-17AF+EEB8-1D0F+78B8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set karma to 10 (if karma is less than 32) + code:9DBC-17AF+FFB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set karma to 20 (if karma is less than 32) + code:CDBC-17AF+FFB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Set karma to 31 (if karma is less than 32) + code:EEBC-17AF+FFB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Add 32 karma (if karma is less than 32) + code:DFBC-17AF+F4B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Add 64 karma (if karma is less than 32) + code:D4BC-17AF+F4B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Add 96 karma (if karma is less than 32) + code:D7BC-17AF+F4B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Add 192 karma (if karma is less than 32) + code:D1BC-17AF+F4B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn powerball spell, level 6 + code:D1BC-17AF+D5B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn heal spell, level 6 + code:D1BC-17AF+D6B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn invisibility spell, level 6 + code:D1BC-17AF+DBB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn armor spell, level 6 + code:D1BC-17AF+DCB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn summon spirit spell, level 6 + code:D1BC-17AF+D8B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn freeze spell, level 6 + code:D1BC-17AF+DAB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn firearms skill, level 5 + code:D9BC-17AF+DFB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn firearms skill, level 10 + code:DCBC-17AF+DFB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn firearms skill, level 15 + code:DEBC-17AF+DFB8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn computer skill, level 6 + code:D1BC-17AF+D0B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn leadership skill, level 6 + code:D1BC-17AF+D9B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn armed combat skill, level 6 + code:D1BC-17AF+D7B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn unarmed combat skill, level 6 + code:D1BC-17AF+D4B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Learn negotiation skill, level 6 + code:D1BC-17AF+D1B8-1D0F+7AB8-1D6F+6EB8-1DDF+53B8-1DAF + cheat + description:Start with computer, firearms skills at level 2 + code:D4BE-4DA4 + cheat + description:Start with computer, firearms skills at level 3 + code:D7BE-4DA4 + cheat + description:Start with computer, firearms skills at level 4 + code:D0BE-4DA4 + cheat + description:Start with computer, firearms skills at level 5 + code:D9BE-4DA4 + cheat + description:Start with computer, firearms skills at level 6 + code:D1BE-4DA4 + cheat + description:Start with 2 strength and charisma + code:D4BC-4404 + cheat + description:Start with 4 strength and charisma + code:D0BC-4404 + cheat + description:Start with 5 strength and charisma + code:D9BC-4404 + cheat + description:Start with 6 strength and charisma + code:D1BC-4404 + cheat + description:Start with 50 stamina + code:74B8-4DA4 + cheat + description:Start with 100 stamina + code:10B8-4DA4 + +cartridge sha256:c73757eea258e169e506eaef989227a59918060f94117917f338183db14c50b6 + title:Shaq Fu (USA) + cheat + description:Infinite continues - Duel Mode + code:C269-EF0D + cheat + description:Blood enabled + code:DDB6-57AF+DDB3-746F + cheat + description:Start with no continues + code:DDA6-5D07 + cheat + description:Start with 1 continues + code:DFA6-5D07 + cheat + description:Start with 5 continues + code:D9A6-5D07 + cheat + description:Start with 9 continues + code:DBA6-5D07 + cheat + description:Start with 15 continues + code:DEA6-5D07 + +cartridge sha256:40e25763288521509b2201f5b4e53f3e3bcdfa92e37cf5eeee4f00d8935d534a + title:Shin Nekketsu Kouha - Kunio-tachi no Banka (Japan) + cheat + description:Invincibility + code:C22B-1466 + cheat + description:Invincibility (alt) + code:7E1202:02 + cheat + description:Infinite health - Kunio + code:7E0094:FF + cheat + description:Infinite health - Riki + code:7E0096:FF + cheat + description:Infinite health - Misako + code:7E0098:FF + cheat + description:Infinite health - Kyouko + code:7E009A:FF + cheat + description:One hit kills + code:7E009C:00+7E009E:00+7E00A0:00+7E00A2:00 + cheat + description:Play as Kunio - Jail Outfit (Safe To Use) + code:7E11DC:00 + cheat + description:Play as Riki - Jail Outfit (Safe To Use) + code:7E11DC:01 + cheat + description:Play as Takayama + code:7E11DC:03 + cheat + description:Play as Cop + code:7E11DC:04 + cheat + description:Play as Gouji + code:7E11DC:05 + cheat + description:Play as Tooru + code:7E11DC:06 + cheat + description:Play as Gouji Henchman + code:7E11DC:07 + cheat + description:Play as Kunio - School Outfit (Safe To Use) + code:7E11DC:08 + cheat + description:Play as Riki - School Outfit (Safe To Use) + code:7E11DC:09 + cheat + description:Play as Misako (Safe To Use) + code:7E11DC:0A + cheat + description:Play as Kyouko (Safe To Use) + code:7E11DC:0B + cheat + description:Play as Daiki Stage 2, Ryuuta Stage 3 + code:7E11DC:0C + cheat + description:Play as Henchman Stage 2 + + code:7E11DC:0E+7E11DC:11+7E11DC:14 + cheat + description:Play as Shingi Henchman + code:7E11DC:17 + cheat + description:Play as Shingi + code:7E11DC:1A + cheat + description:Play as Lisa + code:7E11DC:1B + cheat + description:Play as Sabu + code:7E11DC:1E + cheat + description:Play as Kinji + code:7E11DC:1F + cheat + description:Play as Ken + code:7E11DC:20 + cheat + description:Play as Misuzu + code:7E11DC:21 + cheat + description:Play as Yakuza 1 + code:7E11DC:23 + cheat + description:Play as Yakuza 2 + code:7E11DC:25 + cheat + description:Play as Joe + code:7E11DC:2C + cheat + description:Character color becomes White + code:7E0084:00 + cheat + description:Character color becomes Blue + code:7E0084:01 + cheat + description:Character color becomes Green + code:7E0084:02 + cheat + description:Character color becomes Light Blue + code:7E0084:03 + +cartridge sha256:d09ca5adaee65cfd686742482bc55b1a3ce9bc5ebed61f24c5631555151a7fc7 + title:Side Pocket (USA) + cheat + description:Infinite shots + code:7E1094:0A + cheat + description:Infinite shots (alt) + code:7E1094:10 + cheat + description:Gain lots of bonus shots for every ball you get in + code:7E1097:03 + cheat + description:Always advance to the next level + code:7E10A2:E7+7E10A3:03 + +cartridge sha256:c0bd1b378337c32047a6b7122a3813beb646e496fbdb1fa5c87ab9856271e4c5 + title:SimAnt (USA) + cheat + description:Always have maximum energy + code:DD88-0D0A + cheat + description:Yellow ant always wins + code:DDA7-6402 + +cartridge sha256:e9c0bc05511e05a0d7c3e7cc42e761e1e8e532d46f59b9854b6902e1a2e9dd0a + title:SimCity (USA) + cheat + description:Money doesn't decrease for most types of spending + code:C28A-AD61 + cheat + description:Time goes faster + code:DD67-DFAA + cheat + description:Time goes slower + code:DE67-DFAA + cheat + description:Start easy game with $40,000 + code:0DAB-6D02+BAAB-6D62 + cheat + description:Start easy game with $60,000 + code:1DAB-6D02+3CAB-6D62 + cheat + description:Start easy game with $3,000 + code:86AB-6D02+D8AB-6D62 + cheat + description:Cheat menu at game exit + code:0188E7:A9+0188E8:80+0188E9:F0 + +cartridge sha256:bf74c58e4190faca2f3a967dc190fe529d13887d1262b72e057b5353e43cf67f + title:SimCity 2000 (USA) + cheat + description:Start with $99,999,999 on all the maps except the Land Of Freedom + code:EEF3-8700+3DF3-8760+E9FE-8D60+D9FE-8DA0 + cheat + description:Start with $99,999,999 on the Land Of Freedom + code:EEF3-8D00+3DF3-8D60+E9F3-8F60+D9F3-8FA0 + +cartridge sha256:446a1036d036986fdea7906c83832d3ba79ef63a6ed8c4e88b89ab9cb25daded + title:SimEarth - The Living Planet (USA) + cheat + description:Infinite Omega energy + code:DDB2-F35E + +cartridge sha256:f0d98e9061d0f6a193bb856de8a592f336dada97c41966e8d03119ba97465413 + title:Simpsons, The - Bart's Nightmare (USA) + cheat + description:Infinite lives (Bartman and Itchy and Scratchy sub-games) + code:C2BE-60EA + cheat + description:Infinite Z's (main game) + code:C2C3-6925+C2C3-61B5 + cheat + description:Start with 2 bubbles + code:D46A-D521 + cheat + description:Start with 9 bubbles + code:DB6A-D521 + cheat + description:Infinite life + code:7E0938:0A + cheat + description:Infinite hits + code:7E0514:0B + cheat + description:Infinite 99 Watermelon Seeds left + code:7E0137:63 + cheat + description:Infinite 99 Gum left + code:7E013D:63 + cheat + description:Infinite Bubbles and Seeds + code:89CB-D9B5 + cheat + description:All Pages + code:7E013F:08 + cheat + description:No Pages + code:7E013F:00 + +cartridge sha256:70008efe51185eb0a2f8d8d8ac2bdbb99bd3dfcc169dcc474962f82692998051 + title:Sink or Swim (USA) + cheat + description:Infinite lives + code:7E0972:09 + cheat + description:0 left + code:7E164A:00 + cheat + description:0 to rescue + code:7E1650:00 + cheat + description:9 saved + code:7E164C:09 + +cartridge sha256:e10070f01845505ae8bfdf7b5b492e7209c2ae876f169fb6ff420dea269f4da3 + title:Skuljagger - Revolt of the Westicans (USA) + cheat + description:Invincibility + code:1DCC-A4D4 + cheat + description:Infinite Red Jemeralds + code:D4CB-A7D4 + cheat + description:Don't lose Green Jemeralds when you fall and die + code:C2BB-6FA1 + cheat + description:Infinite time + code:DD6B-DF07 + cheat + description:Infinite lives + code:DDCA-AD04+DDBB-6D61 + cheat + description:Die when touched (regardless of Jemeralds) + code:6DCB-A404+6DCC-A4D4 + cheat + description:No enemies or Jemeralds (good for exploring, disable to advance) + code:8BAB-6DD9 + cheat + description:Red jemeralds set to 10 after being hit (must have at least 1) + code:FFCB-A7D4 + cheat + description:Slower timer + code:5D66-DFA7 + cheat + description:Faster timer + code:F366-DFA7 + cheat + description:Time goes by 2x as fast + code:D46B-DF07 + cheat + description:Time goes by 4x as fast + code:D06B-DF07 + cheat + description:Green Jemeralds worth 3 + code:D7C2-6704 + cheat + description:Green Jemeralds worth 9 + code:DBC2-6704 + cheat + description:Green Jemeralds worth 19 + code:FBC2-6704 + cheat + description:Green Jemeralds worth 25 (extra life on each one) + code:49C2-6704 + cheat + description:10 Green Jemeralds gives an extra life + code:FDC3-6DA4 + cheat + description:50 Green Jemeralds gives an extra life + code:9DC3-6DA4 + cheat + description:1 Green Jemerald gives an extra life + code:DDC3-6F04 + cheat + description:Start with 1 life instead of 5 + code:DF83-D765 + cheat + description:Start with 3 lives + code:D783-D765 + cheat + description:Start with 9 lives + code:DB83-D765 + cheat + description:Start with 19 lives + code:FB83-D765 + cheat + description:Start with 50 lives + code:9D83-D765 + cheat + description:Start with 99 lives + code:BB83-D765 + cheat + description:Invincibility (alt) + code:7E1A02:08 + cheat + description:Infinite time (alt) + code:7E02BE:FF + +cartridge sha256:a4ba1483db79c3f6278082387bce216d8f3e3b11ca32d49516d27f5ac07135a5 + title:Skyblazer (USA) + cheat + description:Invincibility + code:7E0065:9E + cheat + description:Infinite health + code:7EF801:04 + cheat + description:Infinite special power + code:7E1F0D:08 + cheat + description:Infinite Warrior Force + code:7E0089:FF + cheat + description:Have 99 gems + code:7E1F0E:63 + cheat + description:Have Aura Attack + code:7E1F0B:01 + cheat + description:Have Comet Flash + code:7E1F0B:02 + cheat + description:Have Lightning Strike + code:7E1F0B:03 + cheat + description:Have Time Stop + code:7E1F0B:04 + cheat + description:Have Star Fire + code:7E1F0B:05 + cheat + description:Have Warrior Force + code:7E1F0B:06 + cheat + description:Have Heal + code:7E1F0B:07 + cheat + description:Have Fiery Phoenix + code:7E1F0B:08 + cheat + description:All enemies frozen + code:7EFA69:8D+7EFA6A:8D+7EFA6B:8D+7EFA73:8D+7EFA6C:8D+7EFA74:8D+7EFA6D:8D+7EFA75:8D+7EFA6E:8D+7EFA7D:8D+7EFA76:8D+7EFA6F:8D+7EFA7E:8D+7EFA77:8D+7EFA70:8D+7EFA7F:8D+7EFA78:8D+7EFA71:8D+7EFA79:8D+7EFA72:8D+7EFA7A:8D+7EFA7B:8D+7EFA7C:8D+7EFA60:8D+7EFA61:8D+7EFA62:8D+7EFA63:8D+7EFA64:8D+7EFA65:8D+7EFA66:8D+7EFA67:8D+7EFA68:8D + +cartridge sha256:cbca00fa5dfd6c72db2f21d010255657c33f7ac48de2554262035ead11bdf314 + title:Smart Ball (USA) + cheat + description:Infinite lives + code:C2B9-0F0D + cheat + description:Protection from most enemies (lose no hearts) + code:C2BE-A467 + cheat + description:Infinite red balls on pick-up - until continue + code:C266-04A7 + cheat + description:Go to any level + code:7762-040D+DE62-0FAD + cheat + description:Super-jump + code:ECC3-DF6D + cheat + description:Mega-jump + code:E1C3-DF6D + cheat + description:Start with 1 life instead of 3 + code:DF6D-676D + cheat + description:Start with 5 lives + code:D96D-676D + cheat + description:Start with 10 lives + code:DC6D-676D + cheat + description:Start with 25 lives + code:FB6D-676D + cheat + description:Start with 50 lives + code:746D-676D + cheat + description:Start with 99 lives + code:176D-676D + +cartridge sha256:6fe7c8d39fcfab7f0a18e837a7ee0dd162e0557d6989c6e0d10c81616d3a0b8b + title:Soldiers of Fortune (USA) + cheat + description:Infinite lives + code:CBC1-E46F + cheat + description:Smaller food power-ups heal twice as much + code:DCE0-87AD + cheat + description:Smaller food power-ups heal four times as much + code:F0E0-87AD + cheat + description:Large food power-ups heal twice as much + code:F3E9-8FDD + cheat + description:Large food power-ups heal four times as much + code:7AE9-8FDD + cheat + description:Only 3 special powers can be stored instead of 6 (handicap) + code:D0EB-8DDD + cheat + description:Special power power-ups are worth 6 (always fill meter) + code:6DEB-8D0D + cheat + description:Special powers aren't used up + code:3CC6-870D + cheat + description:Mercenary starts with much more health + code:1D4E-5475 + cheat + description:Brigand starts with much more health + code:1D44-87E5 + cheat + description:Gentleman starts with much more health + code:1D41-8F85 + cheat + description:Navvie starts with much more health + code:1D4B-8755 + cheat + description:Thug starts with much more health + code:1D42-8F75 + cheat + description:Scientist starts with much more health + code:1D4D-E4E5 + cheat + description:Extra lives cost 244 instead of 500 + code:DDF6-5D50 + cheat + description:Skill power-ups cost 44 instead of 300 + code:DDF6-5DE0 + cheat + description:Health power-ups cost 1 instead of 75 + code:DFF6-5F70 + cheat + description:Health power-ups cost 25 instead of 75 + code:FBF6-5F70 + cheat + description:Speed power-ups cost 1 instead of 250 + code:DFF6-5F80 + cheat + description:Speed power-ups cost 100 instead of 250 + code:10F6-5F80 + cheat + description:Wisdom power-ups cost 1 instead of 80 + code:DFF6-5470 + cheat + description:Wisdom power-ups cost 25 instead of 80 + code:FBF6-5470 + cheat + description:Special powers cost 1 instead of 150 + code:DFF6-5480 + cheat + description:Special powers cost 50 instead of 150 + code:74F6-5480 + cheat + description:Weapon power-ups cost 1 instead of 250 + code:DFF6-5780 + cheat + description:Weapon power-ups cost 100 instead of 250 + code:10F6-5780 + cheat + description:??? (New Special powers costs 44 instead of 300) + code:DDF6-5750 + cheat + description:Brigand starts with Bomb special power + code:DF40-ED75 + cheat + description:Mercenary starts with Bomb special power + code:DF40-EF75 + cheat + description:Gentleman starts with Bomb special power + code:DF40-E475 + cheat + description:Navvie starts with Bomb special power + code:DF40-E775 + cheat + description:Thug starts with Bomb special power + code:DF49-ED75 + cheat + description:Scientist starts with Bomb special power + code:DF49-EF75 + cheat + description:Brigand starts with Shot Burst special power + code:D440-ED75 + cheat + description:Mercenary starts with Shot Burst special power + code:D440-EF75 + cheat + description:Gentleman starts with Shot Burst special power + code:D440-E475 + cheat + description:Navvie starts with Shot Burst special power + code:D440-E775 + cheat + description:Thug starts with Shot Burst special power + code:D449-ED75 + cheat + description:Scientist starts with Shot Burst special power + code:D449-EF75 + cheat + description:Brigand starts with Map special power (must still destroy nodes special power) + code:D740-ED75 + cheat + description:Mercenary starts with Map special power (must still destroy nodes special power) + code:D740-EF75 + cheat + description:Gentleman starts with Map special power (must still destroy nodes special power) + code:D740-E475 + cheat + description:Navvie starts with Map special power (must still destroy nodes special power) + code:D740-E775 + cheat + description:Thug starts with Map special power (must still destroy nodes special power) + code:D749-ED75 + cheat + description:Scientist starts with Map special power (must still destroy nodes special power) + code:D749-EF75 + cheat + description:Brigand starts with Destroy Nodes special power + code:D040-ED75 + cheat + description:Mercenary starts with Destroy Nodes special power + code:D040-EF75 + cheat + description:Gentleman starts with Destroy Nodes special power + code:D040-E475 + cheat + description:Navvie starts with Destroy Nodes special power + code:D040-E775 + cheat + description:Thug starts with Destroy Nodes special power + code:D049-ED75 + cheat + description:Scientist starts with Destroy Nodes special power + code:D049-EF75 + cheat + description:Brigand starts with Repel Monster special power + code:D940-ED75 + cheat + description:Mercenary starts with Repel Monster special power + code:D940-EF75 + cheat + description:Gentleman starts with Repel Monster special power + code:D940-E475 + cheat + description:Navvie starts with Repel Monster special power + code:D940-E775 + cheat + description:Thug starts with Repel Monster special power + code:D949-ED75 + cheat + description:Scientist starts with Repel Monster special power + code:D949-EF75 + cheat + description:Brigand starts with First Aid special power + code:D140-ED75 + cheat + description:Mercenary starts with First Aid special power + code:D140-EF75 + cheat + description:Gentleman starts with First Aid special power + code:D140-E475 + cheat + description:Navvie starts with First Aid special power + code:D140-E775 + cheat + description:Thug starts with First Aid special power + code:D149-ED75 + cheat + description:Scientist starts with First Aid special power + code:D149-EF75 + cheat + description:Brigand starts with Freeze Monster special power + code:D540-ED75 + cheat + description:Mercenary starts with Freeze Monster special power + code:D540-EF75 + cheat + description:Gentleman starts with Freeze Monster special power + code:D540-E475 + cheat + description:Navvie starts with Freeze Monster special power + code:D540-E775 + cheat + description:Thug starts with Freeze Monster special power + code:D549-ED75 + cheat + description:Scientist starts with Freeze Monster special power + code:D549-EF75 + cheat + description:Brigand starts with Shield special power + code:D640-ED75 + cheat + description:Mercenary starts with Shield special power + code:D640-EF75 + cheat + description:Gentleman starts with Shield special power + code:D640-E475 + cheat + description:Navvie starts with Shield special power + code:D640-E775 + cheat + description:Thug starts with Shield special power + code:D649-ED75 + cheat + description:Scientists starts with Shield special power + code:D649-EF75 + cheat + description:Brigand starts with Party Power special power + code:DB40-ED75 + cheat + description:Mercenary starts with Party Power special power + code:DB40-EF75 + cheat + description:Gentleman starts with Party Power special power + code:DB40-E475 + cheat + description:Navvie starts with Party Power special power + code:DB40-E775 + cheat + description:Thug starts with Party Power special power + code:DB49-ED75 + cheat + description:Scientist starts with Party Power special power + code:DB49-EF75 + cheat + description:Brigand starts with Air Burst special power + code:DC40-ED75 + cheat + description:Mercenary starts with Air Burst special power + code:DC40-EF75 + cheat + description:Gentleman starts with Air Burst special power + code:DC40-E475 + cheat + description:Navvie starts with Air Burst special power + code:DC40-E775 + cheat + description:Thug starts with Air Burst special power + code:DC49-ED75 + cheat + description:Scientist starts with Air Burst special power + code:DC49-EF75 + cheat + description:Brigand starts with Distract Monster special power + code:D840-ED75 + cheat + description:Mercenary starts with Distract Monster special power + code:D840-EF75 + cheat + description:Gentleman starts with Distract Monster special power + code:D840-E475 + cheat + description:Navvie starts with Distract Monster special power + code:D840-E775 + cheat + description:Thug starts with Distract Monster special power + code:D849-ED75 + cheat + description:Scientist starts with Distract Monster special power + code:D849-EF75 + cheat + description:Brigand starts with Molotov special power + code:DA40-ED75 + cheat + description:Mercenary starts with Molotov special power + code:DA40-EF75 + cheat + description:Gentleman starts with Molotov special power + code:DA40-E475 + cheat + description:Navvie starts with Molotov special power + code:DA40-E775 + cheat + description:Thug starts with Molotov special power + code:DA49-ED75 + cheat + description:Scientist starts with Molotov special power + code:DA49-EF75 + cheat + description:Brigand starts with Ground Mine special power + code:D240-ED75 + cheat + description:Mercenary starts with Ground Mine special power + code:D240-EF75 + cheat + description:Gentleman starts with Ground Mine special power + code:D240-E475 + cheat + description:Navvie starts with Ground Mine special power + code:D240-E775 + cheat + description:Thug starts with Ground Mine special power + code:D249-ED75 + cheat + description:Scientist starts with Ground Mine special power + code:D249-EF75 + cheat + description:Brigand starts with Dynamite special power + code:D340-ED75 + cheat + description:Mercenary starts with Dynamite special power + code:D340-EF75 + cheat + description:Gentleman starts with Dynamite special power + code:D340-E475 + cheat + description:Navvie starts with Dynamite special power + code:D340-E775 + cheat + description:Thug starts with Dynamite special power + code:D349-ED75 + cheat + description:Scientist starts with Dynamite special power + code:D349-EF75 + cheat + description:Brigand gets Party Power as a 4th special power + code:DB40-EDE5 + cheat + description:Mercenary gets Party Power as a 4th special power + code:DB40-EFE5 + cheat + description:Navvie gets Party Power as a 3rd special power + code:DB40-E785 + cheat + description:Thug gets Party Power as a 3rd special power + code:DB49-ED85 + cheat + description:Infinite health - P1 + code:7E40F0:64 + cheat + description:Infinite health - P2 or computer partner + code:7E4165:64 + cheat + description:Infinite lives - P1 + code:7E0090:04 + cheat + description:Infinite lives - P2 or computer partner + code:7E0092:04 + cheat + description:Infinite special attacks - P1 + code:7E40FF:06 + cheat + description:Infinite special attacks - P2 or computer partner + code:7E4174:06 + +cartridge sha256:75a7b5b8ad0329dc828d3201089e125fd55fdfc99d4cec704ffcd7e3036c2410 + title:Sonic Blast Man (USA) + cheat + description:Invincibility + code:2DC2-07A7 + cheat + description:Infinite health + code:C2A9-04AD + cheat + description:Infinite health against most enemy hits + code:C2A9-04AD + cheat + description:Infinite health against hits on the head when you're being held + code:C2C3-0DAD + cheat + description:Infinite special + code:C2C3-0464 + cheat + description:Infinite Dynamite Punches + code:C2C3-0464 + cheat + description:Infinite lives + code:DDA5-6F60 + cheat + description:Infinite lives (alt) + code:C2A5-64D0 + cheat + description:Infinite credits + code:C2AC-A4A4 + cheat + description:Hit anywhere + code:47A6-07AD+6DA6-076D + cheat + description:Super glove worth nothing + code:C2A9-0F6F + cheat + description:Hamburger worth nothing + code:DDA4-070F + cheat + description:Hamburger fully restores health + code:9DA4-070F + cheat + description:Apple worth nothing + code:DDAF-040F + cheat + description:Apple fully restores health + code:9DAF-040F + cheat + description:Continue with 3/4 health + code:7AB5-A407 + cheat + description:Continue with 1/2 health + code:46B5-A407 + cheat + description:Continue with 1/4 health + code:F0B5-A407 + cheat + description:Start with 11 lives + code:D76B-D46D + cheat + description:Start with 0 dynamite punches + code:DDAD-ADDF + cheat + description:Start with 5 dynamite punches + code:D9AD-ADDF + cheat + description:Start with 7 dynamite punches + code:D5AD-ADDF + cheat + description:Start with 9 dynamite punches + code:DBAD-ADDF + cheat + description:Start with 3/4 health + code:7AB9-0DD7 + cheat + description:Start with 1/2 health + code:46B9-0DD7 + cheat + description:Start with 1/4 health + code:F0B9-0DD7 + cheat + description:Start on stage 2 + code:33BC-0F0F + cheat + description:Start on stage 3 + code:CBBC-0D6F+3CBC-0FDF+62BC-0F0F+D4BC-0DAF + cheat + description:Start on stage 4 + code:CBBC-0D6F+3CBC-0FDF+62BC-0F0F+D7BC-0DAF + cheat + description:Start on stage 5 + code:CBBC-0D6F+3CBC-0FDF+62BC-0F0F+D0BC-0DAF + +cartridge sha256:efe78f6fc68ddd0f6ef0ad9e0223d9417c14fcadece987dc8f50423fd6723b27 + title:Sonic Blast Man II (USA) + cheat + description:Invincibility + code:C206-5F64 + cheat + description:Infinite health + code:C20B-EFA7 + cheat + description:Infinite lives + code:C295-7F6F + cheat + description:Infinite health - P1 + code:7E0DA5:FF + cheat + description:Infinite health - P2 + code:7E1DA7:FF + cheat + description:Infinite Specials - P1 + code:7E0DAD:63 + cheat + description:Infinite Specials - P2 + code:7E1DAF:63 + cheat + description:Infinite lives - P1 + code:7E0DA9:32 + cheat + description:Infinite lives - P2 + code:7E0DAB:32 + cheat + description:One hit kills on most enemies and bosses + code:7E1377:00+7E1393:00+7E1395:00+7E1391:00+7E138F:00 + cheat + description:Play as Sonic Blast Man - P1 + code:7E0D8D:00 + cheat + description:Play as Sonic Blast Man - P2 + code:7E0D8F:00 + cheat + description:Play as Sonia - P1 + code:7E0D8D:01 + cheat + description:Play as Sonia - P2 + code:7E0D8F:01 + cheat + description:Play as Captain Choyear - P1 + code:7E0D8D:02 + cheat + description:Play as Captain Choyear - P2 + code:7E0D8F:02 + +cartridge sha256:8438da09de8ce9aded3bb08644543f7b60fb60cffc68ce2d67d6a0643f2ecfc2 + title:Soul Blazer (USA) + cheat + description:Invincibility + code:C26E-6DA7+C223-0D07 + cheat + description:Have all spirits after obtaining the first one + code:FEC3-A7D2 + cheat + description:Get max level + code:DDEB-649F + cheat + description:Gems set to 999,999 every time one is obtained + code:DDE8-64BF + cheat + description:10 EXP required instead of 100 for level 2 + code:FDE8-A761+DDE8-A7A1 + cheat + description:180 EXP required instead of 280 for level 3 + code:DFEA-ADA1 + cheat + description:380 EXP required instead of 580 for level 4 + code:D7EA-AFA1 + cheat + description:600 EXP required instead of 1,000 for level 5 + code:D1EA-A4A1 + cheat + description:1,200 EXP required instead of 2,000 for level 6 + code:F4EA-A7A1 + cheat + description:2,400 EXP required instead of 3,200 for level 7 + code:40E2-ADA1 + cheat + description:3,500 EXP required instead of 4,500 for level 8 + code:79E2-AFA1 + cheat + description:4,800 EXP required instead of 5,800 for level 9 + code:06E2-A4A1 + cheat + description:6,600 EXP required instead of 7,600 for level 10 + code:11E2-A7A1 + cheat + description:8,600 EXP required instead of 9,600 for level 11 + code:61E3-ADA1 + cheat + description:10,000 EXP required instead of 12,400 for level 12 + code:DDE3-AFA1 + cheat + description:13,000 EXP required instead of 15,000 for level 13 + code:7DE3-A4A1 + cheat + description:15,000 EXP required instead of 19,000 for level 14 + code:9DE3-A7A1 + cheat + description:Start with 4 HP + code:D0E6-0FB4 + cheat + description:Start with 15 HP + code:DEE6-0FB4 + cheat + description:Start with 25 HP + code:FBE6-0FB4 + cheat + description:Start with 50 HP + code:74E6-0FB4 + cheat + description:Start with 75 HP + code:08E6-0FB4 + cheat + description:Start with 100 HP + code:10E6-0FB4 + cheat + description:Start with 127 HP + code:5EE6-0FB4 + cheat + description:Infinite and max HP + code:7E1B88:64+7E1B8A:64 + cheat + description:Level up more quickly + code:7E1B78:FF + +cartridge sha256:24f3f22949f36ebf8ab4beaa8cba22db107efe7a7585f749343f2860bf041fe1 + title:Space Football - One on One (USA) + cheat + description:Infinite energy + code:C2B9-D7AF + cheat + description:Instant acceleration + code:1B26-A7D7 + cheat + description:No pushback on firing + code:C2C9-D46F + cheat + description:Push forward on firing + code:1BC9-DFAF + +cartridge sha256:dc5353ddc350816619230f25f8c51bddabf7438e6dfba21662eb1c4794856735 + title:Space Invaders - The Original Game (USA) + cheat + description:Infinite lives + code:CB6F-37A9 + cheat + description:Enemies never move + code:7E03D5:00 + cheat + description:Infinite credits + code:7E03BF:02 + +cartridge sha256:f5b7418c00ccac44615cfc57c7e17d57533837056886f6d733e6b714c36dec1f + title:Space Megaforce (USA) + cheat + description:Protection against enemy hits, and weapon level goes to 2 when hit + code:CB68-D4AC+D168-D7DC + cheat + description:Protection against enemy hits, and weapon level goes to 6 when hit + code:CB68-D4AC+D168-D7DC+D16A-D4DC + cheat + description:Infinite bombs + code:DD65-AFAB + cheat + description:Infinite ships + code:DD6D-07AC + cheat + description:Hit anywhere + code:1DCD-6D01+2DCD-6DA1+4ACD-6FD1+C2CD-6DD1+D2CD-6D61 + cheat + description:Power shots (weapon type 6) last until you pick up another weapon or get hit + code:828E-AF6B + cheat + description:Weapon capsules give you weapon type 1 + code:CBC4-0F06+DDC4-0F66 + cheat + description:Weapon capsules give you weapon type 2 + code:CBC4-0F06+DFC4-0F66 + cheat + description:Weapon capsules give you weapon type 3 + code:CBC4-0F06+D4C4-0F66 + cheat + description:Weapon capsules give you weapon type 4 + code:CBC4-0F06+D7C4-0F66 + cheat + description:Weapon capsules give you weapon type 5 + code:CBC4-0F06+D0C4-0F66 + cheat + description:Weapon capsules give you weapon type 6 + code:CBC4-0F06+D9C4-0F66 + cheat + description:Bomb capsules worth 0 + code:DDCE-D4D6 + cheat + description:Bomb capsules worth 2 + code:D4CE-D4D6 + cheat + description:Bomb capsules worth 4 + code:D0CE-D4D6 + cheat + description:Bomb capsules worth 6 + code:D1CE-D4D6 + cheat + description:Start with 0 bombs instead of 3 + code:DDC9-DD06 + cheat + description:Start with 7 bombs + code:D5C9-DD06 + cheat + description:Start with 10 bombs + code:FDC9-DD06 + cheat + description:Start with 25 bombs + code:49C9-DD06 + cheat + description:Start with 50 bombs + code:9DC9-DD06 + cheat + description:Start with 99 bombs + code:BBC9-DD06 + cheat + description:Start with 2 ships + code:DFBE-A4A8 + cheat + description:Start with 8 ships + code:D5BE-A4A8 + cheat + description:Start with 11 ships + code:FDBE-A4A8 + cheat + description:Start with 26 ships + code:49BE-A4A8 + cheat + description:Start with 51 ships + code:9DBE-A4A8 + cheat + description:Start with 76 ships + code:59BE-A4A8 + cheat + description:Start with 100 ships + code:BBBE-A4A8 + cheat + description:Start in area 2 + code:CB6A-0D0D+D46A-0D6D + cheat + description:Start in area 3 + code:CB6A-0D0D+D76A-0D6D + cheat + description:Start in area 4 + code:CB6A-0D0D+D06A-0D6D + cheat + description:Start in area 5 + code:CB6A-0D0D+D96A-0D6D + cheat + description:Start in area 6 + code:CB6A-0D0D+D16A-0D6D + cheat + description:Start in area 7 + code:CB6A-0D0D+D56A-0D6D + cheat + description:Start in area 8 + code:CB6A-0D0D+D66A-0D6D + cheat + description:Start in area 9 + code:CB6A-0D0D+DB6A-0D6D + cheat + description:Start in area 10 + code:CB6A-0D0D+DC6A-0D6D + cheat + description:Start in area 11 + code:CB6A-0D0D+D86A-0D6D + cheat + description:Start in area 12 + code:CB6A-0D0D+DA6A-0D6D + +cartridge sha256:14dc44687c8da35aec63b9edadbaac21bf7293f5171646f614139192e82ab071 + title:Spanky's Quest (USA) + cheat + description:Infinite lives + code:40AC-DF08 + cheat + description:Start with 1 life + code:DD31-AFAD + cheat + description:Start with 6 lives + code:D931-AFAD + cheat + description:Start with 10 lives + code:DB31-AFAD + cheat + description:Start with 1 key in all areas after 1-1 + code:CB3F-0FDF+DF3F-0F0F + cheat + description:Start on area 2-1 + code:CB35-A7AD+DF36-ADDD + cheat + description:Start on area 3-1 + code:CB35-A7AD+D436-ADDD + cheat + description:Start on area 4-1 + code:CB35-A7AD+D736-ADDD + cheat + description:Start on area 5-1 + code:CB35-A7AD+D036-ADDD + +cartridge sha256:eaa06470734ea57eff9b888137aa468fcb7bb149a0870a85e68c9db123de4670 + title:Sparkster (USA) + cheat + description:Invincibility + code:DD27-CFD6 + cheat + description:Invincibility (blinking) + code:CB27-CDA6+D027-CFD6 + cheat + description:Infinite health + code:3C3E-17A8+3C2E-14D6 + cheat + description:Infinite health (alt) + code:7E0691:0E + cheat + description:Infinite lives (alt) + code:7E0168:09 + cheat + description:1 Jewel needed for 1-up + code:7E016A:63 + +cartridge sha256:32d0f1ca5b91fd9b2caf81422fb9e8fb30bc091f0b2a429b9269dd307fcba4fd + title:Spawn (USA) + cheat + description:Invincibility after one hit (invisible) + code:C203-84D1 + cheat + description:Almost invincible (blinking) + code:3C03-8F61 + cheat + description:Infinite health + code:C208-87D1 + cheat + description:Don't blink after getting hit + code:FDDB-5FB9 + cheat + description:Falling doesn't use life points + code:C2F4-7FD1 + cheat + description:Special moves don't use life points + code:C27D-8701 + cheat + description:Some bullets do 2x damage + code:D6D7-8F20 + cheat + description:Some bullets do no damage + code:DDD7-8F20 + cheat + description:Some bullets kill you + code:EED7-8F20 + cheat + description:Some enemy punches electrocute you + code:DB78-84B0 + cheat + description:Some enemy punches do no damage + code:DD78-84B0 + cheat + description:Some enemy punches kill you + code:EE78-84B0 + cheat + description:Guys with pipes do 2x damage + code:DBB0-EFA3+DBCF-8763 + cheat + description:Guys with pipes do no damage + code:DDB0-EFA3+DDCF-8763 + cheat + description:Guys with pipes kill + code:EEB0-EFA3+EECF-8763 + cheat + description:Flaming bottles do 2x damage + code:DB4B-7DF1+DB43-E4F9 + cheat + description:Flaming bottles do no damage + code:DD4B-7DF1+DD43-E4F9 + cheat + description:Flaming bottles kill + code:EE4B-7DF1+EE43-E4F9 + cheat + description:Start with 1/4 health + code:FDB0-E4DB + cheat + description:Start with 1/2 health + code:4CB0-E4DB + cheat + description:Start with 3/4 health + code:73B0-E4DB + cheat + description:Invincibility + code:7E1F56:1F + cheat + description:Infinite health (alt) + code:7E1F00:63 + +cartridge sha256:fe2371bed45f5e244ce3ef8585894c0ffa4272e3f58c2f4795ef91fb1ee54b15 + title:Spectre (USA) + cheat + description:Infinite ammo + code:C2C8-D4DD + cheat + description:Infinite lives + code:E08F-D40D + cheat + description:Infinite health + code:E0C1-6707 + cheat + description:Infinite hyperspace + code:C2C0-DDDF + cheat + description:Freeze bonus timer + code:C232-ADA4 + cheat + description:Infinite custom shield + code:7E1B42:0A + cheat + description:Infinite custom speed + code:7E1B44:0A + cheat + description:Infinite custom ammo + code:7E1B46:0A + +cartridge sha256:68a51b7a06b6a9e7100a89521e52b5c467c46c828c0f6504bee677beac2aa6fd + title:Speedy Gonzales - Los Gatos Bandidos (USA) (Rev 1) + cheat + description:Infinite health + code:C2B4-CFAD + cheat + description:Infinite time + code:3CA9-C76D + cheat + description:Infinite continues + code:C266-44A1 + cheat + description:Start with 99 lives + code:176C-44DD + cheat + description:Invincibility after first hit + code:7E099E:FF + cheat + description:Infinite health (alt) + code:7E08CC:05 + cheat + description:Infinite lives + code:7E0935:03 + cheat + description:Infinite time + code:7E0934:00 + cheat + description:Have 5 hearts + code:7E08CE:05 + cheat + description:Hyper Speedy Gonzalez + code:7E0052:00 + cheat + description:Keep Speedy Shoes until end of stage on pick-up + code:7E08B0:FF + cheat + description:Start on Sleepy Rock Part 1 + code:7E0098:00 + cheat + description:Start on Ancient Keep Part 1 + code:7E0098:02 + cheat + description:Start on Snowy Cabins Part 1 + code:7E0098:04 + cheat + description:Start on Galactical Galazies Part 1 + code:7E0098:06 + cheat + description:Start on Surely Wood Part 1 + code:7E0098:08 + cheat + description:Start on Snowy Cabins Part 2 + code:7E0098:0A + cheat + description:Start on Fiesta City Part 1 + code:7E0098:0C + cheat + description:Start on Ye Olde Bounty Part 1 + code:7E0098:0E + cheat + description:Start on Fiesta City Part 2 + code:7E0098:10 + cheat + description:Start on Ancient Keep Part 2 + code:7E0098:12 + cheat + description:Start on Ye Olde Bounty Part 2 + code:7E0098:14 + cheat + description:Start on Ye Olde Bounty Part 3 + code:7E0098:16 + cheat + description:Start on Surely Wood Part 2 + code:7E0098:18 + cheat + description:Start on Sleepy Rock Part 2 + code:7E0098:1A + cheat + description:Start on Surely Wood Part 3 + code:7E0098:1C + cheat + description:Start on Surely Wood? Cat Boss + code:7E0098:1E + cheat + description:Start on Ship Cat Boss + code:7E0098:20 + cheat + description:Start on Galactical Galazies? Cat Boss + code:7E0098:22 + cheat + description:Start on Galactical Galazies Part 2 + code:7E0098:24 + cheat + description:Start on Ye Olde Bounty Part 5 + code:7E0098:26 + +cartridge sha256:df02d0f4f40e2732138309d38e91b48aef482490979007ecb63359a35115dfd4 + title:Speedy Gonzales - Los Gatos Bandidos (USA) + cheat + description:Invincibility after first hit + code:7E099E:FF + cheat + description:Infinite health + code:7E08CC:05 + cheat + description:Infinite lives + code:7E0935:03 + cheat + description:Infinite time + code:7E0934:00 + cheat + description:Have 5 hearts + code:7E08CE:05 + cheat + description:Hyper Speedy Gonzalez + code:7E0052:00 + cheat + description:Keep Speedy Shoes until end of stage on pick-up + code:7E08B0:FF + cheat + description:Start on Sleepy Rock Part 1 + code:7E0098:00 + cheat + description:Start on Ancient Keep Part 1 + code:7E0098:02 + cheat + description:Start on Snowy Cabins Part 1 + code:7E0098:04 + cheat + description:Start on Galactical Galazies Part 1 + code:7E0098:06 + cheat + description:Start on Surely Wood Part 1 + code:7E0098:08 + cheat + description:Start on Snowy Cabins Part 2 + code:7E0098:0A + cheat + description:Start on Fiesta City Part 1 + code:7E0098:0C + cheat + description:Start on Ye Olde Bounty Part 1 + code:7E0098:0E + cheat + description:Start on Fiesta City Part 2 + code:7E0098:10 + cheat + description:Start on Ancient Keep Part 2 + code:7E0098:12 + cheat + description:Start on Ye Olde Bounty Part 2 + code:7E0098:14 + cheat + description:Start on Ye Olde Bounty Part 3 + code:7E0098:16 + cheat + description:Start on Surely Wood Part 2 + code:7E0098:18 + cheat + description:Start on Sleepy Rock Part 2 + code:7E0098:1A + cheat + description:Start on Surely Wood Part 3 + code:7E0098:1C + cheat + description:Start on Surely Wood? Cat Boss + code:7E0098:1E + cheat + description:Start on Ship Cat Boss + code:7E0098:20 + cheat + description:Start on Galactical Galazies? Cat Boss + code:7E0098:22 + cheat + description:Start on Galactical Galazies Part 2 + code:7E0098:24 + cheat + description:Start on Ye Olde Bounty Part 5 + code:7E0098:26 + +cartridge sha256:2701e94631ae1c43ca0ccef2b50bc0341a4111b31b885fa372ab5b4a49b06942 + title:SpellCraft (USA) (Proto) + cheat + description:Infinite health + code:7E018D:99 + cheat + description:Quick enemy death + code:7E0193:00 + cheat + description:Fast level up + code:7E00FD:FF + cheat + description:Infinite Stones + code:7E0296:09 + cheat + description:Infinite Jewels + code:7E0298:09 + cheat + description:Infinite Candles + code:7E029A:09 + cheat + description:Infinite Powders + code:7E029C:09 + +cartridge sha256:f05d777e3de69aab18d336cac0af07f794f8d00090d085f86cebaed3679cabad + title:Spider-Man (USA) + cheat + description:Stay invincible after death + code:C2CF-C70D + cheat + description:Infinite health + code:C9BB-3DD8 + cheat + description:Infinite lives + code:C2B1-3468 + cheat + description:Infinite webbing + code:C3CA-1F6F+C2CC-44A7+C3CC-1FAF+C2CF-4707 + cheat + description:Gain webbing instead of losing it + code:33CA-1F6F+33CC-44A7+33CC-1FAF+33CF-4707 + cheat + description:Hit anywhere + code:6D39-4FA7+6D3D-4767+DD30-47A7+DD30-4F67 + cheat + description:Increase diagnol webbing with R button + code:33CA-1F6F + cheat + description:Increase straight webbing with X button + code:33CC-44A7 + +cartridge sha256:964d21996e385e032b5d18baf716692ba1db780245cd71956c212045c1b8eb9a + title:Spider-Man-Venom - Maximum Carnage (USA) + cheat + description:Invincibility + code:C264-CFD0 + cheat + description:Infinite health + code:C2A1-1F01 + cheat + description:Infinite lives + code:C2BB-1D61 + cheat + description:Infinite hero icons on pick-up + code:8220-47AB + cheat + description:Super punch + code:DBA6-17F5 + cheat + description:Power hit lasts longer + code:D06A-4F09 + cheat + description:Jump higher + code:7D80-3F61 + cheat + description:Start with 2x health + code:1DCC-C460 + cheat + description:Start with 3x health + code:BDCC-C460 + cheat + description:Start with 1 life + code:DFC8-CDD0 + cheat + description:Start with 6 lives + code:D1C8-CDD0 + cheat + description:Start with 9 lives + code:DBC8-CDD0 + cheat + description:Start with 9 continues + code:DBC8-CF60 + cheat + description:Start with 6 continues + code:D1C8-CF60 + cheat + description:Infinite health (alt) + code:7E0B7C:2C + cheat + description:Infinite lives (alt) + code:7E0990:05 + cheat + description:Infinite accuracy + code:7E1CCA:58 + cheat + description:Have 7 Black Cats with infinite usage + code:7E0B18:07 + cheat + description:Have 7 Cloaks with infinite usage + code:7E0B1A:07 + cheat + description:Have 7 Dagger with infinite usage + code:7E0B1C:07 + cheat + description:Have 7 Morbius with infinite usage + code:7E0B1E:07 + cheat + description:Have 7 Firestar with infinite usage + code:7E0B20:07 + cheat + description:Have 7 Captain Americas with infinite usage + code:7E0B22:07 + cheat + description:Have 7 Iron Fist with infinite usage + code:7E0B24:07 + cheat + description:Have 7 Deathlok with infinite usage + code:7E0B26:07 + cheat + description:Have 7 Venom With Sonic Gun with infinite usage + code:7E0B28:07 + +cartridge sha256:63210a91573fa8e19592f2e6c746a400831d804c00453739447d2df32e731df7 + title:Spider-Man-X-Men - Arcade's Revenge (USA) + cheat + description:Invincibility after first hit (blinking) - Spider-Man + code:C261-A044 + cheat + description:Infinite health against most hits - Spider-Man + code:DDCB-6144 + cheat + description:Protects Spider-Man from ground hazard (looks like silver weeds) + code:C2CC-A917 + cheat + description:Infinite lives - Spider-Man + code:C266-D51D + cheat + description:Infinite lives - Gambit + code:C26D-090A + cheat + description:Infinite lives - Wolverine, Cyclops, Storm + code:C2C2-D767 + cheat + description:Spider-Man jumps higher (if you jump too high in some places you die) + code:CB69-0937+E669-0147 + cheat + description:Start with 1 life instead of 3 + code:DD68-646D + cheat + description:Start with 5 lives + code:D068-646D + cheat + description:Start with 7 lives + code:D168-646D + cheat + description:Start with 10 lives + code:DB68-646D + cheat + description:Start with 26 lives + code:FB68-646D + cheat + description:Start with 51 lives + code:7468-646D + cheat + description:Start with 100 lives + code:1768-646D + cheat + description:Invincibility - Spider-Man + code:7E10F6:FF + cheat + description:Infinite health - Spider-Man + code:7E10F8:FF + cheat + description:Infinite health - Wolverine, Cyclops, Storm + code:7E0B29:64 + cheat + description:Infinite health - Gambit + code:7E119E:96 + cheat + description:Infinite lives - Everyone + code:7E0100:09 + cheat + description:Infinite multibolt - Storm + code:7E14F2:01 + cheat + description:99 stars - Gambit + code:7E11AA:63 + cheat + description:Infinite cards - Gambit + code:7E11A0:32 + cheat + description:Infinite joker wild cards - Gambit + code:7E11A2:09 + cheat + description:Stop giant spiked wheel in first stage - Gambit + code:7E11F9:FF + +cartridge sha256:fe10238ae42ed9eb4d906a81dd50ebe585140982cdfe266308ce1f16e78e6903 + title:Spindizzy Worlds (USA) + cheat + description:Faster G.E.R.A.L.D. + code:D46F-6FDD + cheat + description:Slower timer + code:D0BD-64DF + cheat + description:More fuel lost from falling off landscape + code:4D6C-DFD7 + cheat + description:Less fuel lost from falling off landscape + code:D96C-DFD7 + cheat + description:Almost zero fuel lost from falling off landscape + code:DD6C-DFD7 + cheat + description:Don't lose fuel from anything + code:4AEC-DDA4 + +cartridge sha256:e0196201e432fa33d46a2681f84fe6a0b5f952ba43f8e4dc325f892bb4a0b39b + title:Spirou (Europe) (En,Fr,De,Es) + cheat + description:Infinite lives + code:7E064C:03 + +cartridge sha256:3857b5294ea8f7468849437bb2d8271564e8a0ff30774622e9c872bcbd53a84d + title:Star Fox (USA) + cheat + description:Infinite Shield + code:79DB-2286 + cheat + description:Infinite Shield (alt) + code:46DB-2286 + cheat + description:Infinite Shield - Slippy + code:0DFC-FA8C + cheat + description:Infinite Shield - Falco + code:0DFC-FA5C + cheat + description:Infinite Shield - Peppy + code:0DFC-FA7C + cheat + description:Infinite Bombs + code:D9FC-9EEB + cheat + description:Infinite lives + code:DBF3-BE8B + cheat + description:Have Double Blaster + code:F4F2-F38B+DFF2-F35B + cheat + description:Infinite Shield (alt 2) + code:7E0396:35 + cheat + description:Infinite Bombs (alt) + code:7E15AF:05 + cheat + description:Infinite lives (alt) + code:7E16EE:0A + cheat + description:Have Double Blaster (alt) + code:7E14DA:12 + cheat + description:Have Double Blaster B and infinite Shield + code:7E14D9:03 + +cartridge sha256:82e39dfbb3e4fe5c28044e80878392070c618b298dd5a267e5ea53c8f72cc548 + title:Star Fox (USA) (Rev 2) + cheat + description:Infinite Shield + code:79DB-2286 + cheat + description:Infinite Shield (alt) + code:46DB-2286 + cheat + description:Infinite Shield - Slippy + code:0DFC-FA8C + cheat + description:Infinite Shield - Falco + code:0DFC-FA5C + cheat + description:Infinite Shield - Peppy + code:0DFC-FA7C + cheat + description:Infinite Shield (alt 2) + code:7E0396:35 + +cartridge sha256:2c0bac12a7866fad1cb306da768a201c12f2520332df1ef51cba1576db21ff06 + title:Star Fox (USA) (Super Weekend Competition) + cheat + description:Infinite Shield + code:7E0396:28 + cheat + description:Infinite Bombs + code:7E15AF:04 + cheat + description:Infinite time (minutes) + code:7EF0DA:09 + cheat + description:Infinite time (seconds tens) + code:7EF0DC:09 + cheat + description:Infinite time (seconds ones) + code:7EF0DB:09 + cheat + description:Have Double Blaster + code:7E14D9:01 + +cartridge sha256:efae37be832d0ea1490784d57bef00761a8bf0b5bcef9c23f558e063441c3876 + title:Star Ocean (Japan) + cheat + description:No random battles + code:6D5D-7F66 + cheat + description:Fight one battle for max level / EXP + code:DD1E-E4D5 + cheat + description:Fight one battle for max Fol + code:DD1F-E465 + cheat + description:View status screen for max strength, constitution, agility and stamina (These affect the base stat, making it savable. Stamina won't appear updated until you turn the codes off and re-enter that character's status screen) + code:DD48-54CF+9843-774D+1F47-5F3D+1243-5DCD+2C4A-5F3D + cheat + description:Infinite items when using item creation skills + code:8E23-87C6 + +cartridge sha256:3a16ad45ae3d89b13c9e53e21c2a4c725ff7cec7fbe7896d538d163f92cb4aac + title:Star Trek - Deep Space Nine - Crossroads of Time (USA) + cheat + description:Invincibility + code:3C3E-0915+3C3E-09C5 + cheat + description:Invincibility after first hit + code:C23E-0935 + cheat + description:Infinite energy + code:C23C-6545 + cheat + description:Sisko looks like O'brien + code:D0BF-0D6F + cheat + description:Start with 1/4 energy + code:FDBF-0F04+FDBF-076F + cheat + description:Start with 1/2 energy + code:F2BF-0F04+F2BF-076F + cheat + description:Start with 3/4 energy + code:45BF-0F04+45BF-076F + +cartridge sha256:22c907b56ac6f414365801ed375c3fbf75696ce7f34ec89e1724628dc5622957 + title:Star Trek - The Next Generation - Future's Past (USA) + cheat + description:Away Team - Medical packs aren't used up + code:DD81-47DB+DD88-4DDB + cheat + description:Away Team - Start each away mission with 1 medical pack + code:DF2A-1DD7 + cheat + description:Away Team - Start each away mission with 2 medical packs + code:D42A-1DD7 + cheat + description:Away Team - Start each away mission with 4 medical packs (only 3 shown) + code:D02A-1DD7 + cheat + description:Away Team - Start each away mission with 5 medical packs (only 3 shown) + code:D92A-1DD7 + cheat + description:Away Team - Phaser power doesn't go down + code:DDAF-446C + cheat + description:Away Team - Start away missions with phasers at 1/2 power + code:F62A-1467 + cheat + description:Away Team - Start away missions with phasers at 3/4 power + code:402A-1467 + cheat + description:Away Team - Start away missions with phasers at 1/4 power + code:DA2A-1467 + cheat + description:Away Team - Medical packs heal more + code:6D86-4FAB + cheat + description:Away Team - Medical packs heal twice as much + code:D486-44DB + cheat + description:Away Team - Medical packs heal completely + code:D786-44DB + cheat + description:Away Team - Crew members are immune to enemy fire + code:8EA4-4FD6 + cheat + description:Space Combat - Forward torpedoes reload much faster + code:DFB2-1DF7 + cheat + description:Space Combat - Forward torpedoes reload faster + code:D4B2-1DF7 + cheat + description:Space Combat - Aft torpedoes reload much faster + code:DFB8-1FF7 + cheat + description:Space Combat - Aft torpedoes reload faster + code:D4B8-1FF7 + cheat + description:Space Combat - Forward torpedoes don't require recharging + code:C26C-3FFD + cheat + description:Space Combat - Aft torpedoes don't require recharging + code:C267-342D + cheat + description:Space Combat - Enemy shields regenerate at half speed + code:D6B4-1F27 + cheat + description:Space Combat - Enemy shields regenerate at 1/4 speed + code:D0B4-1F27 + cheat + description:Space Combat - Enemy shields don't regenerate + code:DDB4-1F27 + cheat + description:Space Combat - Enemy shields regenerate faster + code:F6B4-1F27 + cheat + description:Space Combat - Forward phasers never lose power + code:3C6A-14FF + cheat + description:Space Combat - Forward phasers don't recharge + code:C2B3-4DB7 + cheat + description:Space Combat - Aft phasers never lose power + code:3C69-17BF + cheat + description:Space Combat - Aft phasers don't recharge + code:C2BE-44F7 + cheat + description:Space Combat - Torpedoes do half damage + code:D764-1D24 + cheat + description:Space Combat - Torpedoes do less damage + code:D064-1D24 + cheat + description:Space Combat - Torpedoes do slightly more damage + code:D564-1D24 + cheat + description:Space Combat - Torpedoes do more damage + code:D664-1D24 + cheat + description:Space Combat - Torpedoes do much more damage + code:DB64-1D24 + cheat + description:Space Combat - Torpedoes do double damage + code:DA64-1D24 + +cartridge sha256:91f938b4989215b1cd39635797f23b59b9d7b6d36e583f9eb69d022abe537bfc + title:Steel Talons (USA) + cheat + description:Infinite Rockets + code:7E025C:09 + cheat + description:Infinite fuel and no damage + code:7E0262:50 + cheat + description:Always finish mission in 10 seconds + code:7E0258:0A + +cartridge sha256:dad9c116283322d5a13fd659874c681582abdff3df182cc4c90511d33fb7110a + title:Stone Protectors (USA) + cheat + description:Invincibility (blinking) + code:CBB6-0F07+D9B6-0F67+B2B6-0FA7+4022-D764 + cheat + description:Don't lose health from special moves + code:8281-0D67 + cheat + description:Infinite lives - P1 + code:C281-D467 + cheat + description:Infinite health - P1 + code:7E13CC:B2 + +cartridge sha256:910a29f834199c63c22beddc749baba746da9922196a553255deade59f4fc127 + title:Street Fighter Alpha 2 (USA) + cheat + description:Invincibility (except throws and Akuma's special moves) + code:3CC6-5DDD+3DC6-5D0D+6DC6-5D6D+DBC6-5DAD+3D80-7F6D+DD80-7FAD+D580-74DD + cheat + description:Hit anywhere (except projectiles) - P1 + code:3DC7-8D0D+6DC7-8D6D+BDC7-8FDD+DBC7-8DAD + +cartridge sha256:2b34161e96ef3f0f48cecd67e531a9bb94310652d8686f301bac426e4ab97e77 + title:Street Fighter II (USA) + cheat + description:Invincibility (except against throws) - P1 + code:6D27-6704+DF27-6764+4039-670D + cheat + description:Win 1 bout to win the match instead of 2 out of 3 (disable before fighting M. Bison) + code:DF80-AD64 + cheat + description:Hit anywhere (except projectiles) - P1 + code:3D29-A4A7+8D29-A767+DD29-A7D7+D329-A707 + cheat + description:Dizziness wears off very quickly + code:EDBE-0F09 + cheat + description:Dizziness lasts longer (on harder levels, won't work on computer) + code:C9BE-0DA9 + cheat + description:Championship mode on + code:4DC6-6493 + cheat + description:Advance to next level when you continue (disable before you continue on M. Bison's stage) + code:6DCF-D764+FFCF-D7A4 + cheat + description:High throw and grab damage + code:3CA4-DD67+FEA4-DFD7 + cheat + description:Minimum throw and grab damage + code:3CA4-DD67+EEA4-DFD7 + cheat + description:Die after 2 hits - both players + code:503E-04DF + cheat + description:Round number does not advance (can't fight to a draw) + code:C2CC-A7DF + cheat + description:1 draw ends fight in VS. battle + code:DF81-A704 + cheat + description:Most punches and kicks do no damage + code:893E-04DF + cheat + description:Players move faster + code:1C65-DF00 + cheat + description:Some special moves are faster + code:D965-DF00 + cheat + description:Can do special moves in the air - both players + code:DD61-6DA9 + cheat + description:Dragon punch does not go as high + code:73A5-DF60 + cheat + description:Dragon punch goes higher + code:2AA5-DF60 + cheat + description:Some special moves are easier to perform (E Honda's Sumo Head Butt, Blanka's Rolling Attack, Guile's Flash Kick and Sonic Boom, Chun Li's Whirlwind Kick) + code:DD84-DD01 + cheat + description:No pause after throwing a Fireball + code:DFA0-DDA0+ADA0-DFD0 + cheat + description:Players can hit each other no matter where they are + code:6D25-A467+6F25-A4A7 + cheat + description:Do special moves by just pressing buttons (may make Fireballs lower) + code:DAB8-A761 + cheat + description:Fireballs are lower to the ground + code:DDB8-ADF3 + cheat + description:Fireballs are higher off the ground + code:1DB8-ADF3 + cheat + description:Fireballs, Sonic Booms and Yoga Fires always go to the right (thrown to the left, they go backwards) + code:DDE3-DF01 + cheat + description:Light Fireballs, Sonic Booms and Yoga Fires are slower + code:EEB8-A793 + cheat + description:Light Fireballs, Sonic Booms and Yoga Fires are faster + code:EBB8-A793 + cheat + description:Light Fireballs, Sonic Booms and Yoga Fires are super fast + code:EDB8-A793 + cheat + description:Medium Fireballs, Sonic Booms and Yoga Fires are slower + code:EEB8-A723 + cheat + description:Medium Fireballs, Sonic Booms and Yoga Fires are faster + code:EBB8-A723 + cheat + description:Medium Fireballs, Sonic Booms and Yoga Fires are super fast + code:EDB8-A723 + cheat + description:Hard Fireballs, Sonic Booms and Yoga Fires are slower + code:EEBA-AD93 + cheat + description:Hard Fireballs, Sonic Booms and Yoga Fires are faster + code:EBBA-AD93 + cheat + description:Hard Fireballs, Sonic Booms and Yoga Fires are super fast + code:EDBA-AD93 + cheat + description:Light Sumo Head Butts and Rolling Attacks are slower + code:DDB1-D4F3+EEB1-D7B3 + cheat + description:Light Sumo Head Butts and Rolling Attacks are faster + code:DBB1-D4F3+EBB1-D7B3 + cheat + description:Light Sumo Head Butts and Rolling Attacks are super fast + code:F9B1-D4F3+EDB1-D7B3 + cheat + description:Medium Sumo Head Butts and Rolling Attacks are slower + code:DDB1-D4B3+EEB5-DDF3 + cheat + description:Medium Sumo Head Butts and Rolling Attacks are faster + code:DCB1-D4B3+E5B5-DDF3 + cheat + description:Medium Sumo Head Butts and Rolling Attacks are super fast + code:F1B1-D4B3+33B5-DDF3 + cheat + description:Hard Sumo Head Butts and Rolling Attacks are slower + code:DDB1-D7F3+EEB5-DDB3 + cheat + description:Hard Sumo Head Butts and Rolling Attacks are faster + code:D8B1-D7F3+E9B5-DDB3 + cheat + description:Hard Sumo Head Butts and Rolling Attacks are super fast + code:F5B1-D7F3+32B5-DDB3 + cheat + description:Most special moves disabled (computer can still do them, Zangief can still do Spinning Clothesline) + code:6DA4-6707 + cheat + description:Invisible Fireballs, Sonic Booms, Yoga Fires and Yoga Flames + code:CB61-07A4 + cheat + description:No Fireballs, Sonic Booms or Yoga Fires, makes Yoga Flame invisible + code:1868-0D6C + cheat + description:Always fight Ryu + code:CBA0-AF64+EEA0-AFA4 + cheat + description:Always fight Honda + code:CBA0-AF64+DDA0-AFA4 + cheat + description:Always fight Blanka + code:CBA0-AF64+DFA0-AFA4 + cheat + description:Always fight Guile + code:CBA0-AF64+D4A0-AFA4 + cheat + description:Always fight Ken + code:CBA0-AF64+D7A0-AFA4 + cheat + description:Always fight Chun-Li + code:CBA0-AF64+D0A0-AFA4 + cheat + description:Always fight Zangief + code:CBA0-AF64+D9A0-AFA4 + cheat + description:Always fight Dhalsim + code:CBA0-AF64+D1A0-AFA4 + cheat + description:Always fight Balrog + code:CBA0-AF64+DBA0-AFA4 + cheat + description:Always fight Vega + code:CBA0-AF64+DCA0-AFA4 + cheat + description:Always fight Sagat + code:CBA0-AF64+D6A0-AFA4 + cheat + description:Fight M. Bison + code:B9A0-AF04 + cheat + description:Always fight on bonus stage 1 + code:DDA4-A404+6DA4-A764 + cheat + description:Always fight on bonus stage 2 + code:DDA7-AF04+DDA7-A4A4 + cheat + description:90 seconds per round instead of 99 + code:BD62-672A + cheat + description:80 seconds per round + code:6D62-672A + cheat + description:70 seconds per round + code:5D62-672A + cheat + description:60 seconds per round + code:1D62-672A + cheat + description:50 seconds per round + code:9D62-672A + cheat + description:40 seconds per round + code:0D62-672A + cheat + description:30 seconds per round + code:7D62-672A + cheat + description:20 seconds per round + code:4D62-672A + cheat + description:10 seconds per round + code:FD62-672A + cheat + description:99 seconds in 1st bonus round instead of 40 + code:BB63-6D2A + cheat + description:90 seconds in 1st bonus round + code:BD63-6D2A + cheat + description:80 seconds in 1st bonus round + code:6D63-6D2A + cheat + description:70 seconds in 1st bonus round + code:5D63-6D2A + cheat + description:60 seconds in 1st bonus round + code:1D63-6D2A + cheat + description:50 seconds in 1st bonus round + code:9D63-6D2A + cheat + description:30 seconds in 1st bonus round + code:7D63-6D2A + cheat + description:20 seconds in 1st bonus round + code:4D63-6D2A + cheat + description:10 seconds in 1st bonus round + code:FD63-6D2A + cheat + description:Start with no health - both players + code:DDAC-AFD4 + cheat + description:Start with no health - P1 + code:DDAC-AF64 + cheat + description:Start with 3/4 health (1/4 damage) - both players + code:60AC-AFD4 + cheat + description:Start with 1/2 health (1/2 damage) - both players + code:96AC-AFD4 + cheat + description:Start with 1/4 health (3/4 damage) - both players + code:4AAC-AFD4 + +cartridge sha256:3e487f8ba48c0b5e31744e3281d6bce375089db6075c8eb3d9a929376b817381 + title:Street Fighter II Turbo (USA) + cheat + description:Invincibility (except against throws) - P1 + code:6D93-54DF+DF93-540F+CB99-5767+DD99-57A7+DB91-5DD7+4091-5D07+3C91-5DA7 + cheat + description:Infinite time + code:DD05-7F04 + cheat + description:Hit anywhere (except projectiles) - P1 + code:3D98-8704+8D9A-8DD4+DD98-8764+D598-87A4 + cheat + description:Some special moves can be performed in the air (Don't perform Vega's wall leap) + code:DDF1-7D60 + cheat + description:Most attacks do no damage (throws still work) + code:891F-84AD + cheat + description:Throws do no damage + code:C734-7405 + cheat + description:1st throws do more damage (if you have enough health), others do less damage + code:F034-7405 + cheat + description:Players can walk through each other + code:DD3F-EFAD + cheat + description:1st hit of any kind defeats opponent + code:DD18-570D + cheat + description:Winner of 2nd round wins the battle + code:DF04-5DAF + cheat + description:Enable 10 star turbo mode + code:ADFC-E40D+F9FC-E46D + cheat + description:No charging required for special moves (except Balrog's turn punch power) + code:D071-E460 + cheat + description:Hard special moves become light + code:DD75-8460 + cheat + description:Hard special moves become medium + code:D475-8461 + cheat + description:Hard special moves become disabled + code:D675-8462 + cheat + description:Invisible players + code:8ED2-87A9 + cheat + description:Most special moves go nowhere + code:C933-7DA9 + cheat + description:Fireballs go nowhere + code:C9B8-77A5 + cheat + description:Hard Hurricane Kicks go faster and farther (to the right only) + code:D039-14AD + cheat + description:Ryu's hard Dragon Punch doesn't go as far + code:DF30-1DAD + cheat + description:Ryu's hard Dragon Punch goes farther + code:D630-1DAD + cheat + description:Ryu's medium Dragon Punch doesn't go as far + code:DF30-1D0D + cheat + description:Ryu's medium Dragon Punch goes farther + code:D630-1D0D + cheat + description:Ryu's light Dragon Punch goes farther + code:D637-17AD + cheat + description:Ryu jumps backward farther + code:D526-1DAF + cheat + description:Ryu jumps forward farther + code:E525-14AF + cheat + description:Ken jumps backward farther + code:D52D-CDAF + cheat + description:Ken jumps forward farther + code:E52E-14AF + cheat + description:Ken's hard Dragon Punch doesn't go as far + code:DF30-17AD + cheat + description:Ken's hard Dragon Punch goes farther + code:D330-17AD + cheat + description:Ken's medium Dragon Punch doesn't go as far + code:DF30-170D + cheat + description:Ken's medium Dragon Punch goes farther + code:D830-170D + cheat + description:Ken's light Dragon Punch goes farther + code:D630-14AD + cheat + description:Hard projectiles go faster (except tiger shots) + code:3E31-37AD + cheat + description:Hard projectiles go slower (except tiger shots) + code:EE31-37AD + cheat + description:Medium projectiles go faster (except tiger shots) + code:3E31-370D + cheat + description:Medium projectiles go slower (except tiger shots) + code:EE31-370D + cheat + description:Light projectiles go faster (except tiger shots) + code:3E31-34AD + cheat + description:Light projectiles go slower (except tiger shots) + code:EE31-34AD + cheat + description:Edmond Honda's hard Sumo Head Butts are faster + code:DE35-1FAD + cheat + description:Edmond Honda's hard Sumo Head Butts are slower + code:DF35-1FAD + cheat + description:Edmond Honda's medium Sumo Head Butts are faster + code:DE35-1F0D + cheat + description:Edmond Honda's medium Sumo Head Butts are slower + code:DF35-1F0D + cheat + description:Edmond Honda's light Sumo Head Butts are faster + code:DE35-1DAD + cheat + description:Edmond Honda's light Sumo Head Butts are slower + code:DF35-1DAD + cheat + description:Edmond Honda's hard Sumo Smashes are faster + code:F436-1DDD + cheat + description:Edmond Honda's medium Sumo Smashes are faster + code:F435-176D + cheat + description:Edmond Honda's light Sumo Smashes are faster + code:F435-17DD + cheat + description:Sagat's hard Tiger Uppercut goes farther + code:D63B-C70D + cheat + description:Sagat's medium Tiger Uppercut goes farther + code:D63B-C4AD + cheat + description:Sagat's light Tiger Uppercut goes farther + code:D63B-C40D + cheat + description:Sagat's high Tiger Shots are disabled (you can still do the move but no projectile comes out) + code:D439-340D + cheat + description:Sagat's hard Tiger Knee goes farther + code:D838-CF0D + cheat + description:Sagat's medium Tiger Knee goes farther + code:D83C-C70D + cheat + description:Sagat's light Tiger Knee goes farther + code:D83C-CF0D + cheat + description:M. Bison's hard Psycho Crusher goes slower + code:DF39-C40D + cheat + description:M. Bison's hard Psycho Crusher goes faster + code:DC39-C40D + cheat + description:M. Bison's medium Psycho Crusher goes slower + code:DF39-CFAD + cheat + description:M. Bison's medium Psycho Crusher goes faster + code:DC39-CFAD + cheat + description:M. Bison's light Psycho Crusher goes slower + code:DF39-CF0D + cheat + description:M. Bison's light Psycho Crusher goes faster + code:DC39-CF0D + cheat + description:M. Bison's hard Scissor Kick goes slower (not in normal mode) + code:DF31-CD6D + cheat + description:M. Bison's hard Scissor Kick goes faster (not in normal mode) + code:DC31-CD6D + cheat + description:M. Bison's medium Scissor Kick goes slower (not in normal mode) + code:DF31-CDDD + cheat + description:M. Bison's medium Scissor Kick goes faster (not in normal mode) + code:DC31-CDDD + cheat + description:M. Bison's light Scissor Kick goes slower (not in normal mode) + code:DF39-C76D + cheat + description:M. Bison's light Scissor Kick goes faster (not in normal mode) + code:DC39-C76D + cheat + description:Balrog's first Dash Punch goes slower + code:DF69-7DD1 + cheat + description:Balrog's first Dash Punch goes faster + code:D869-7DD1 + cheat + description:Balrog's first Turn Punch goes slower (and a little backward) + code:D432-CF0D + cheat + description:Balrog's first Turn Punch goes faster + code:DC32-CF0D + cheat + description:Chun Li's hard Whirlwind Kick goes farther + code:DC38-1F6D + cheat + description:Chun Li's medium Whirlwind Kick doesn't go as far + code:DF38-1FDD + cheat + description:Chun Li's medium Whirlwind Kick goes farther + code:DC38-1FDD + cheat + description:Chun Li's light Whirlwind Kick doesn't go as far + code:DF38-1D6D + cheat + description:Chun Li's light Whirlwind Kick goes farther + code:DC38-1D6D + cheat + description:Blanka's hard Rolling Attack goes slower + code:DF3B-14DD + cheat + description:Blanka's hard Rolling Attack goes faster + code:DC3B-14DD + cheat + description:Blanka's medium Rolling Attack goes slower + code:DF3B-1F6D + cheat + description:Blanka's medium Rolling Attack goes faster + code:DC3B-1F6D + cheat + description:Blanka's light Rolling Attack goes slower + code:DF3B-1FDD + cheat + description:Blanka's light Rolling Attack goes faster + code:DC3B-1FDD + cheat + description:Blanka's hard Vertical Rolling Attack doesn't go as far + code:DF3C-1D0D + cheat + description:Blanka's hard Vertical Rolling Attack goes out farther + code:DA3C-1D0D + cheat + description:Blanka's medium Vertical Rolling Attack doesn't go as far + code:DF3B-17AD + cheat + description:Blanka's medium Vertical Rolling Attack goes out farther + code:DA3B-17AD + cheat + description:Blanka's light Vertical Rolling Attack doesn't go as far + code:DF3B-170D + cheat + description:Blanka's light Vertical Rolling Attack goes out farther + code:DA3B-170D + cheat + description:Start with 90 seconds + code:BDA3-176D + cheat + description:Start with 70 seconds + code:5DA3-176D + cheat + description:Start with 50 seconds + code:9DA3-176D + cheat + description:Start with 30 seconds + code:7DA3-176D + cheat + description:Start with 10 seconds + code:FDA3-176D + cheat + description:Start with 3/4 health + code:6091-E76D + cheat + description:Start with 1/2 health + code:9691-E76D + cheat + description:Start with 1/4 health + code:4A91-E76D + cheat + description:1st bonus round is 99 seconds + code:BBAE-1DDD + cheat + description:1st bonus round is 80 seconds + code:6DAE-1DDD + cheat + description:1st bonus round is 60 seconds + code:1DAE-1DDD + cheat + description:1st bonus round is 20 seconds + code:4DAE-1DDD + cheat + description:2nd bonus round is 99 seconds + code:BBAE-1D6D + cheat + description:2nd bonus round is 80 seconds + code:6DAE-1D6D + cheat + description:2nd bonus round is 60 seconds + code:1DAE-1D6D + cheat + description:2nd bonus round is 20 seconds + code:4DAE-1D6D + cheat + description:Infinite health - P1 + code:7E0530:63 + cheat + description:No health (disable during match) - P2 + code:7E0730:00 + cheat + description:Infinite time (alt) + code:7E18F3:99 + cheat + description:Select same character - both players + code:7E1848:20 + cheat + description:Enable 10 star turbo mode (alt) + code:7E1C87:32 + cheat + description:Dizzy from every knockdown - P1 + code:7E05B3:01 + cheat + description:Dizzy from every knockdown - P2 + code:7E07B3:01 + +cartridge sha256:05f14e6ed3394d9273e2397769a8acf1a9db646be6066e82269521e8eec53562 + title:Strike Gunner S.T.G (USA) + cheat + description:Infinite lives - P1 + code:C2B4-076F + cheat + description:Infinite lives - P2 + code:C2B8-046F + cheat + description:Infinite continues + code:C262-D9E6 + cheat + description:Infinite special weapon energy - P1 + code:C2EA-D46D + cheat + description:Infinite special weapon energy - P2 + code:C2E4-0DAD + cheat + description:Start on stage 2 + code:CB69-D40D+DF69-D46D+3C69-D4AD + cheat + description:Start on stage 3 + code:CB69-D40D+D469-D46D+3C69-D4AD + cheat + description:Start on stage 4 + code:CB69-D40D+D769-D46D+3C69-D4AD + cheat + description:Start on stage 5 + code:CB69-D40D+D069-D46D+3C69-D4AD + cheat + description:Start on stage 6 + code:CB69-D40D+D969-D46D+3C69-D4AD + cheat + description:Invincibility after first life - P1 + code:7E024E:05 + cheat + description:Invincibility after first life - P2 + code:7E024F:05 + +cartridge sha256:c04d80b84514202ff319384ca20641eb0189e975eed5612915bd9c224b2ab30a + title:Stunt Race FX (USA) (Rev 1) + cheat + description:Always first + code:182E-07FE + cheat + description:Choose any car + code:2DAE-AD42 + cheat + description:Infinite lives + code:7E0DF8:09 + cheat + description:Infinite boost - P1 + code:7E0E05:48+7E0E06:48 + cheat + description:Infinte time - minutes + code:7E0E66:00 + cheat + description:Infinite time - seconds + code:7E0E64:00 + cheat + description:Infinite time extended + code:7E19EE:99 + cheat + description:Have all stars collected + code:7E19EC:64 + cheat + description:Remove car body + code:7E2005:5C + +cartridge sha256:e9c406d4f773697b9b671e7ddf2207c9d0ab242d7f23e502cdd453fbb264d392 + title:Sunset Riders (USA) + cheat + description:Invincibility + code:3366-CD69 + cheat + description:Infinite lives + code:8232-3D0F + +cartridge sha256:190999122aacc2cff20c5677b3f60ed938d8a36b696d16cc1bf416705efe151e + title:Super Adventure Island (USA) + cheat + description:Infinite lives + code:C2B3-D46D + cheat + description:Infinite credits + code:C2CD-0F0D + cheat + description:Fruit restores full time + code:CBBE-DF94+FDBE-DFB4 + cheat + description:Super-jump (don't use the game's super-jump feature) + code:798C-DF0D + cheat + description:Mega-jump (don't use the game's super-jump feature) + code:408C-DF0D + cheat + description:Hit anywhere + code:2D83-64A2+6D83-6462+C983-6402+DD21-0D0D+F383-67D2 + cheat + description:Multi-jump + code:4D8C-640D+E28C-646D+C2E4-0DD7+E6E4-0D07+D8E4-0D67+06E4-0DA7+DCE4-0FD7+FDE4-0F07+D9E4-0F67+CBE4-0FA7+DDE4-04D7+ECE4-0407+B9E4-0467+FCE4-04A7+16E4-07D7+1DE4-0707+4D8C-64DD + cheat + description:Don't lose all weapon power when you die (may give you unusual weapons) + code:79C0-A7DD+79C6-A4DD + cheat + description:Start with 1 life instead of 3 + code:DD6A-646F + cheat + description:Start with 5 lives + code:D06A-646F + cheat + description:Start with 10 lives + code:DB6A-646F + cheat + description:Start with 15 lives + code:D36A-646F + cheat + description:Start with 25 lives + code:F66A-646F + cheat + description:Start with 50 lives + code:7F6A-646F + cheat + description:Start with 99 lives + code:146A-646F + cheat + description:Start with 1 credit + code:DD6A-67AF + cheat + description:Start with 6 credits + code:D96A-67AF + cheat + description:Start in area 1, stage 2 + code:D766-0FD7 + cheat + description:Start in area 1 bonus round + code:D966-0FD7 + cheat + description:Start in area 1, stage 3 + code:D566-0FD7 + cheat + description:Start in area 2, stage 1 + code:DC66-0FD7 + cheat + description:Start in area 2, stage 2 + code:DA66-0FD7 + cheat + description:Start in area 2 bonus round + code:D366-0FD7 + cheat + description:Start in area 2, stage 3 + code:FF66-0FD7 + cheat + description:Start in area 3, stage 1 + code:F066-0FD7 + cheat + description:Start in area 3, stage 2 + code:F666-0FD7 + cheat + description:Start in area 3, stage 3 + code:FC66-0FD7 + cheat + description:Start in area 4, stage 1 + code:F266-0FD7 + cheat + description:Start in area 4, stage 2 + code:FE66-0FD7 + cheat + description:Start in area 4 bonus round + code:4D66-0FD7 + cheat + description:Start in area 4, stage 3 + code:4066-0FD7 + cheat + description:Start in area 5, stage 1 + code:4566-0FD7 + cheat + description:Start in area 5, stage 2 + code:4B66-0FD7 + cheat + description:Start in area 5, stage 3 + code:4866-0FD7 + cheat + description:Start in area 5, bonus round + code:4266-0FD7 + cheat + description:Invincibility and Infinite time + code:7E0D6B:FF + cheat + description:Invincibility and always have Skateboard (disable at end of level) + code:7E0D6F:01 + cheat + description:Infinite time (disable at end of level) + code:7E0D6C:11 + cheat + description:Infinite lives (alt) + code:7E030D:03 + cheat + description:Have Boomerang after obtaining any weapon icon + code:7E0D75:01 + cheat + description:Have Fireball after obtaining any weapon icon + code:7E0D75:02 + cheat + description:Have Boomerang Fireball after obtaining any weapon icon + code:7E0D75:03 + cheat + description:Have Hammer after obtaining any weapon icon + code:7E0D75:04 + cheat + description:Start on last boss + code:008D84:30 + +cartridge sha256:eaf1b83e95d8a04f9a84d4960cf87cc182fc60ef07be35eb8929c4033d6fef67 + title:Super Adventure Island II (USA) + cheat + description:Infinite health + code:C29B-EF0F + cheat + description:Almost invincible after one hit + code:C2D6-8FAB + cheat + description:Stacks of cash + code:CB45-ED6D + cheat + description:Small potions don't restore health + code:C2B4-7D8E + cheat + description:Fall slowly + code:DFF1-770B + cheat + description:Don't fall at all (disable to touch the ground again) + code:DDF1-770B + cheat + description:Have no Weapon + code:7E044D:01 + cheat + description:Have Silver Sword + code:7E044E:01 + cheat + description:Have Fire Sword + code:7E044F:01 + cheat + description:Have Ice Sword + code:7E0450:01 + cheat + description:Have Thunder Sword + code:7E0451:01 + cheat + description:Have Crystal Sword + code:7E0452:01 + cheat + description:Have Power Sword + code:7E0453:01 + cheat + description:Have Light Sword + code:7E0454:01 + cheat + description:Have Dagger + code:7E0455:01 + cheat + description:Have Fireballs + code:7E0456:01 + cheat + description:Have Boomerang + code:7E0457:01 + cheat + description:Have Ax + code:7E0458:01 + cheat + description:Have Shovel + code:7E0459:01 + cheat + description:Have no Armor + code:7E045A:01 + cheat + description:Have Fire Armor + code:7E045B:01 + cheat + description:Have Ice Armor + code:7E045C:01 + cheat + description:Have Aqua Armor + code:7E045D:01 + cheat + description:Have Light Armor + code:7E045E:01 + cheat + description:Have no Shield + code:7E045F:01 + cheat + description:Have Fire Shield + code:7E0460:01 + cheat + description:Have Ice Shield + code:7E0461:01 + cheat + description:Have Aqua Shield + code:7E0462:01 + cheat + description:Have Light Shield + code:7E0463:01 + cheat + description:Have no Equipment + code:7E0465:01 + cheat + description:Have Magic Wand + code:7E0464:01 + cheat + description:Have Ice Bell + code:7E0466:01 + cheat + description:Have Sun Ring + code:7E0467:01 + cheat + description:Have Power Fan + code:7E0468:01 + cheat + description:Have Elven Flute + code:7E0469:01 + cheat + description:Have Sky Bell + code:7E046A:01 + cheat + description:Have Light Stone + code:7E046B:01 + cheat + description:Have Sun Stone + code:7E046C:01 + cheat + description:Have Star Stone + code:7E046D:01 + cheat + description:Have Aqua Stone + code:7E046E:01 + cheat + description:Have Moon Stone + code:7E046F:01 + cheat + description:Have Thunder Spell + code:7E0470:01 + cheat + description:Have Star Spell + code:7E0471:01 + cheat + description:Have Sun Spell + code:7E0472:01 + cheat + description:Have Aqua Spell + code:7E0473:01 + cheat + description:Have Moon Spell + code:7E0474:01 + cheat + description:Have Shove + code:7E047D:01 + cheat + description:Have Up Jab + code:7E047E:01 + cheat + description:Have Down Jab + code:7E047F:01 + cheat + description:Light Gate down + code:7E0131:01 + cheat + description:Sun Gate down + code:7E0132:01 + cheat + description:Star Gate down + code:7E0133:01 + cheat + description:Aqua Gate down + code:7E0134:01 + cheat + description:Moon Gate down + code:7E0135:01 + +cartridge sha256:0deb7a91fbe5848f1733ce668daaa49b0dad3d821bacc0791837c1ba15e60d7c + title:Super Alfred Chicken (USA) + cheat + description:Infinite time + code:C2C4-4DA5 + cheat + description:Infinite lives + code:C2BC-3FD5 + cheat + description:Infinite lives (alt) + code:7E0012:04 + cheat + description:Infinite time (alt) + code:7E0017:09 + cheat + description:Infinite balloons + code:C2C3-4D09 + +cartridge sha256:e57aa265b2fbfb7ee7f5488a3df06ae771db202d59ebbd13df8fc2db80a856f3 + title:Super Back to the Future Part II (Japan) + cheat + description:Invincibility + code:7E1401:FF + cheat + description:Infinite health + code:7E009A:03 + +cartridge sha256:1622371a5a4001fff9690323e89b7a8d449cdc3cae6dcd1249f0c7dc8c651d33 + title:Super Baseball Simulator 1.000 (USA) + cheat + description:Infinite added points + code:DDCD-646C + cheat + description:Fewer "HR" points to distribute - standard game + code:783E-DF6C + cheat + description:Fewer "R" points to distribute - standard game + code:9D3E-D4DC + cheat + description:Fewer "F" points to distribute - standard game + code:F03E-D46C + cheat + description:More "AV" points to distribute - moderate game + code:DB3F-070C + cheat + description:More "HR" points to distribute - moderate game + code:DF3F-07AC+BD3F-076C + cheat + description:More "R" points to distribute - moderate game + code:1634-0DDC+DF34-0D0C + cheat + description:More "F" points to distribute - moderate game + code:1034-0D6C + +cartridge sha256:a8239355631d303ecebfd43fc14e80f148e4ac9937234e29cc87d6f939b033a0 + title:Super Bases Loaded (USA) + cheat + description:Game lasts 1 inning + code:DDA1-A46D+DFA0-A76D+DFE0-6F6D + cheat + description:Game lasts 2 innings + code:D4A1-A46D+D7A0-A76D+D7E0-6F6D + cheat + description:Game lasts 3 innings + code:D0A1-A46D+D9A0-A76D+D9E0-6F6D + cheat + description:Game lasts 5 innings + code:D6A1-A46D+DBA0-A76D+DBE0-6F6D + cheat + description:Game lasts 7 innings + code:DAA1-A46D+D2A0-A76D+D2E0-6F6D + cheat + description:1 strike and batter is out + code:DFAF-6F67+DDA2-07D7 + cheat + description:2 strikes and batter is out + code:D4AF-6F67+DFA2-07D7 + cheat + description:4 strikes and batter is out + code:D0AF-6F67+D7A2-07D7 + cheat + description:5 strikes and batter is out + code:D9AF-6F67+D0A2-07D7 + cheat + description:7 strikes and batter is out + code:D5AF-6F67+D1A2-07D7 + cheat + description:9 strikes and batter is out + code:DBAF-6F67+D6A2-07D7 + cheat + description:Batter never strikes out + code:C2E8-DF0D + cheat + description:Batter walks on 1 ball + code:DFA5-6F07+DDA7-6767 + cheat + description:Batter walks on 2 balls + code:D4A5-6F07+DFA7-6767 + cheat + description:Batter walks on 3 balls + code:D7A5-6F07+D4A7-6767 + cheat + description:Batter walks on 5 balls + code:D9A5-6F07+D0A7-6767 + cheat + description:Batter walks on 6 balls + code:D1A5-6F07+D9A7-6767 + cheat + description:Batter walks on 9 balls + code:DBA5-6F07+D6A7-6767 + cheat + description:Batter never walks + code:C2EA-D40D + cheat + description:1 out per inning + code:DDE7-07AD + cheat + description:2 outs per inning + code:DFE7-07AD + cheat + description:4 outs per inning + code:D7E7-07AD + cheat + description:5 outs per inning + code:D0E7-07AD + cheat + description:7 outs per inning + code:D1E7-07AD + cheat + description:9 outs per inning + code:D6E7-07AD + +cartridge sha256:b21a161fed748920e54cd72c54095416b1d999636e0388d7d147884779c52833 + title:Super Bases Loaded 3 - License to Steal (USA) + cheat + description:No strikes + code:C26E-4D01 + cheat + description:One strike to strike out + code:DF6E-44D1 + cheat + description:Ten strikes to strike out + code:DC6E-44D1 + cheat + description:Infinite strikes gives P1 a homerun + code:556E-4D61 + cheat + description:Infinite strikes gives opponent a homerun + code:566E-4D61 + cheat + description:Walk on one ball + code:DF6F-C461 + cheat + description:Walk on ten balls + code:DC6F-C461 + cheat + description:Infinite balls gives P1 a homerun + code:556F-CFD1 + cheat + description:Infinite balls gives opponent a homerun + code:566F-CFD1 + +cartridge sha256:165938810948f3226f7446978fa36ae8bc781616d95b39cd126d5c8afbf6e2ee + title:Super Batter Up (USA) + cheat + description:Batter never walks + code:C2B2-0D6A + cheat + description:Batter never strikes out + code:C2BD-64DA + cheat + description:1 ball per walk + code:DFB2-040A + cheat + description:2 balls per walk + code:D4B2-040A + cheat + description:3 balls per walk + code:D7B2-040A + cheat + description:5 balls per walk + code:D9B2-040A + cheat + description:6 balls per walk + code:D1B2-040A + cheat + description:7 balls per walk + code:D5B2-040A + cheat + description:1 strike per out + code:DFBD-67AA + cheat + description:2 strikes per out + code:D4BD-67AA + cheat + description:4 strikes per out + code:D0BD-67AA + cheat + description:5 strikes per out + code:D9BD-67AA + +cartridge sha256:1735f790ebcfa1bed2430aecde3abaf24c88ff99aa0186736f8f36b674bc9350 + title:Super Battletank - War in the Gulf (USA) (Rev 1) + cheat + description:Infinite health against most enemies and mines + code:C9AC-0D67 + cheat + description:Infinite weapon ammo (except Smoke Screens and Machine Gun) + code:4ABD-DDA4 + cheat + description:More Machine Gun ammo on stages 1-4 + code:EE2E-D4D4 + cheat + description:Less Machine Gun ammo on stages 1-4 + code:482E-D4D4 + cheat + description:More Cannon ammo on each mission + code:1022-D7D4 + cheat + description:Less Cannon ammo on each mission + code:FB22-D7D4 + cheat + description:More Laser Shells on each mission + code:D923-DF04 + cheat + description:No Laser Shells on each mission + code:DD23-DF04 + cheat + description:More Smoke Screens on each mission + code:D923-D7A4 + cheat + description:No Smoke Screens on each mission + code:DD23-D7A4 + cheat + description:Infinite health against most enemies and mines (alt) + code:00CDA2:A5 + cheat + description:Infinite Fuel + code:7E05C4:FF + cheat + description:Infinite 120mm Cannon + code:7E049E:42 + cheat + description:Infinite Laser Missiles + code:7E04A0:01 + cheat + description:Infinite Smoke Screens + code:7E04A1:01 + cheat + description:Infinite 7.62mm Machine Gun + code:7E04A2:96 + +cartridge sha256:94496e73fc7fdf2f72f16bf2becb0c3935db2ebd97555eac73b63400acbceec6 + title:Super Battletank - War in the Gulf (USA) + cheat + description:Infinite health against most enemies and mines + code:C9AC-0D67 + cheat + description:Infinite weapon ammo (except Smoke Screens and Machine Gun) + code:4ABD-DDA4 + cheat + description:More Machine Gun ammo on stages 1-4 + code:EE2E-D4D4 + cheat + description:Less Machine Gun ammo on stages 1-4 + code:482E-D4D4 + cheat + description:More Cannon ammo on each mission + code:1022-D7D4 + cheat + description:Less Cannon ammo on each mission + code:FB22-D7D4 + cheat + description:More Laser Shells on each mission + code:D923-DF04 + cheat + description:No Laser Shells on each mission + code:DD23-DF04 + cheat + description:More Smoke Screens on each mission + code:D923-D7A4 + cheat + description:No Smoke Screens on each mission + code:DD23-D7A4 + cheat + description:Infinite health against most enemies and mines (alt) + code:00CDA2:A5 + cheat + description:Infinite Fuel + code:7E05C4:FF + cheat + description:Infinite 120mm Cannon + code:7E049E:42 + cheat + description:Infinite Laser Missiles + code:7E04A0:01 + cheat + description:Infinite Smoke Screens + code:7E04A1:01 + cheat + description:Infinite 7.62mm Machine Gun + code:7E04A2:96 + +cartridge sha256:b68e865b0b5fe6af421a171e94fb1cb0006ae3e412b6361f6f858c44adaa304b + title:Super Battletank 2 (USA) + cheat + description:Infinite hits + code:7E00AD:00 + cheat + description:Infinite health in 3rd person mode + code:7E0A2A:00 + cheat + description:Infinite 120mm bullets + code:7E10E3:09 + cheat + description:Infinite 120mm bullets in 3rd person mmode + code:7E0A10:09 + cheat + description:Infinite 7.62mm bullets + code:7E10E7:09 + cheat + description:Infinite 7.62mm bullets in 3rd person mode + code:7E0A0E:09 + cheat + description:Infinite Phalanx + code:7E10E8:09 + cheat + description:Infinite Scope + code:7E10E9:09 + cheat + description:Infinite Smoke + code:7E10E6:09 + cheat + description:Infinite LGM + code:7E10E5:09 + cheat + description:Infinite Patriot + code:7E10E4:09 + +cartridge sha256:4efab3f49cbe91ec77b6cba747ddfedfdc0b080c755a8b6ba51234f0676c000f + title:Super Bomberman (USA) + cheat + description:Invincibility (normal game) + code:89FC-77FF + cheat + description:Infinite lives (normal game) + code:89FE-57B4 + cheat + description:Invincibility - P1 + code:7E0D79:80 + cheat + description:Invincibility - P2 + code:7E0DB9:80 + cheat + description:Invincibility - P3 + code:7E0DF9:80 + cheat + description:Invincibility - P4 + code:7E0E39:80 + cheat + description:Invincibility, Kick Bomb, Punch Glove, Bomb Walk, Brick Walk - P1 + code:7E0D79:E3 + cheat + description:Invincibility, Kick Bomb, Punch Glove, Bomb Walk, Brick Walk - P2 + code:7E0DB9:E3 + cheat + description:Invincibility, Kick Bomb, Punch Glove, Bomb Walk, Brick Walk - P3 + code:7E0DF9:E3 + cheat + description:Invincibility, Kick Bomb, Punch Glove, Bomb Walk, Brick Walk - P4 + code:7E0E39:E3 + cheat + description:Infinite time + code:7E0D3B:FF + cheat + description:Infinite lives - P1 + code:7E0D7D:09 + cheat + description:Infinite lives - P2 + code:7E0DBD:09 + cheat + description:Max bomb power - P1 + code:7E0D71:09 + cheat + description:Max bomb power - P2 + code:7E0DB1:09 + cheat + description:Max bomb power - P3 + code:7E0DF1:09 + cheat + description:Max bomb power - P4 + code:7E0E31:09 + cheat + description:Max bomb quantity - P1 + code:7E0D70:09 + cheat + description:Max bomb quantity - P2 + code:7E0DB0:09 + cheat + description:Max bomb quantity - P3 + code:7E0DF0:09 + cheat + description:Max bomb quantity - P4 + code:7E0E30:09 + cheat + description:Max speed - P1 + code:7E0D72:09 + cheat + description:Max speed - P2 + code:7E0DB2:09 + cheat + description:Max speed - P3 + code:7E0DF2:09 + cheat + description:Max speed - P4 + code:7E0E32:09 + cheat + description:Have Detonator - P1 + code:7E0D73:09 + cheat + description:Have Detonator - P2 + code:7E0DB3:09 + cheat + description:Have Detonator - P3 + code:7E0DF3:09 + cheat + description:Have Detonator - P4 + code:7E0E33:09 + cheat + description:Have red bombs - P1 + code:7E0D78:09 + cheat + description:Have red bombs - P2 + code:7E0DB8:09 + cheat + description:Have red bombs - P3 + code:7E0DF8:09 + cheat + description:Have red bombs - P4 + code:7E0E38:09 + cheat + description:Have 9,000,000 points - P1 + code:7E0D5B:09 + cheat + description:Have 9,000,000 points - P2 + code:7E0D9B:09 + +cartridge sha256:0a4b4a783a7faf6ada3e1326ecf85de77e8c2a171659b42a78a1fae43f806ca6 + title:Super Bomberman 2 (USA) + cheat + description:Invincibility - P1 + code:7E80EF:01 + cheat + description:Invincibility - P2 + code:7E81EF:01 + cheat + description:Invincibility - P3 + code:7E82EF:01 + cheat + description:Invincibility - P4 + code:7E83EF:01 + cheat + description:Infinite time + code:7E5E12:3B + cheat + description:Infinite lives + code:7E1C6C:09 + cheat + description:Move fast + code:7E80F0:02 + cheat + description:Move faster + code:7E80F0:03 + cheat + description:Move fastest + code:7E80F0:04 + cheat + description:Max bomb power - P1 + code:7E80F2:09 + cheat + description:Max bomb power - P2 + code:7E81F2:09 + cheat + description:Max bomb power - P3 + code:7E82F2:09 + cheat + description:Max bomb power - P4 + code:7E83F2:09 + cheat + description:Max bomb quantity - P1 + code:7E80F1:09 + cheat + description:Max bomb quantity - P2 + code:7E81F1:09 + cheat + description:Max bomb quantity - P3 + code:7E82F1:09 + cheat + description:Max bomb quantity - P4 + code:7E83F1:09 + cheat + description:Max speed - P1 + code:7E80F0:06 + cheat + description:Max speed - P2 + code:7E81F0:06 + cheat + description:Max speed - P3 + code:7E82F0:06 + cheat + description:Max speed - P4 + code:7E83F0:06 + cheat + description:Have Detonator - P1 + code:7E80F3:01 + cheat + description:Have Detonator - P2 + code:7E81F3:01 + cheat + description:Have Detonator - P3 + code:7E82F3:01 + cheat + description:Have Detonator - P4 + code:7E83F3:01 + cheat + description:Have Power Bombs - P1 + code:7E80F3:02 + cheat + description:Have Power Bombs - P2 + code:7E81F3:02 + cheat + description:Have Power Bombs - P3 + code:7E82F3:02 + cheat + description:Have Power Bombs - P4 + code:7E83F3:02 + cheat + description:Have Super Bombs - P1 + code:7E80F3:04 + cheat + description:Have Super Bombs - P2 + code:7E81F3:04 + cheat + description:Have Super Bombs - P3 + code:7E82F3:04 + cheat + description:Have Super Bombs - P4 + code:7E83F3:04 + cheat + description:Have Gel Bombs - P1 + code:7E80F3:08 + cheat + description:Have Gel Bombs - P2 + code:7E81F3:08 + cheat + description:Have Gel Bombs - P3 + code:7E82F3:08 + cheat + description:Have Gel Bombs - P4 + code:7E83F3:08 + cheat + description:Have Punch Glove - P1 + code:7E80FE:01 + cheat + description:Have Punch Glove - P2 + code:7E81FE:01 + cheat + description:Have Punch Glove - P3 + code:7E82FE:01 + cheat + description:Have Punch Glove - P4 + code:7E83FE:01 + cheat + description:Have Kick Bomb - P1 + code:7E80FF:01 + cheat + description:Have Kick Bomb - P2 + code:7E81FF:01 + cheat + description:Have Kick Bomb - P3 + code:7E82FF:01 + cheat + description:Have Kick Bomb - P4 + code:7E83FF:01 + cheat + description:Have Bomb Walk - P1 + code:7E80FA:01 + cheat + description:Have Bomb Walk - P2 + code:7E81FA:01 + cheat + description:Have Bomb Walk - P3 + code:7E82FA:01 + cheat + description:Have Bomb Walk - P4 + code:7E83FA:01 + cheat + description:Have Brick Walk - P1 + code:7E80FB:01 + cheat + description:Have Brick Walk - P2 + code:7E81FB:01 + cheat + description:Have Brick Walk - P3 + code:7E82FB:01 + cheat + description:Have Brick Walk - P4 + code:7E83FB:01 + cheat + description:Have Poison Status - P1 + code:7E80F5:01 + cheat + description:Have Poison Status - P2 + code:7E81F5:01 + cheat + description:Have Poison Status - P3 + code:7E82F5:01 + cheat + description:Have Poison Status - P4 + code:7E83F5:01 + cheat + description:Have 4,000,000 points - P1 + code:7E5DEF:A7 + cheat + description:Have 9,000,000 points - P2 + code:7E0D9B:09 + cheat + description:Jump ability in battle-mode - all players + code:7E1C00:02+EFFF04:32 + +cartridge sha256:21d4a72461d8680cf75cf3b8eba42e13127815bc17b6249d89a5e39beb3f1406 + title:Super Bonk (USA) + cheat + description:Press up to fly on any level + code:CB31-4F08+3C31-4FA8 + cheat + description:Infinite max life + code:7E101C:1E + cheat + description:Max life + code:7E101D:1E + cheat + description:Always have 99 lives + code:7E101E:63 + cheat + description:Always have 99 Smileys + code:7E1022:63 + +cartridge sha256:946de556b4f877e54e16b5c828db89c038e50349cfd0ddf8ea96b6541f9d70fa + title:Super Bowling (USA) + cheat + description:No spin on ball + code:4ACA-0464 + cheat + description:Faster spin meter + code:D1C5-DDAD + cheat + description:Slower spin meter + code:D4C5-DDAD + cheat + description:Really slow spin meter + code:DFC5-DDAD + cheat + description:Faster power meter + code:D1C5-D4DD + cheat + description:Slower power meter + code:D4C5-D4DD + cheat + description:Really slow power meter + code:DFC5-D4DD + +cartridge sha256:dc233b2805f7f73b454b53e45eef50df18932a1753fc0b7bc846bbd70a8993c3 + title:Super Buster Bros. (USA) (Rev 1) + cheat + description:Extra credit after 2 food items instead of 10 + code:D42B-A7D0 + cheat + description:Extra credit after 4 food items + code:D02B-A7D0 + cheat + description:Extra credit after 6 food items + code:D12B-A7D0 + cheat + description:Extra credit after 8 food items + code:D62B-A7D0 + cheat + description:Food items never earn extra credit + code:3C2B-A460 + cheat + description:Invincibility + code:7E0100:05 + cheat + description:Shield always on + code:7E0134:02 + cheat + description:Normal shot + code:7E0131:00 + cheat + description:Double shot + code:7E0131:02 + cheat + description:Grappling shot + code:7E0131:04 + cheat + description:Gun shot + code:7E0131:06 + +cartridge sha256:5965bde449ff775c1a0d9fd3cf2fb8c51a86b44ad1942dfb5c14a91f103be030 + title:Super Buster Bros. (USA) + cheat + description:Infinite lives + code:DDB2-07A4 + cheat + description:Infinite credits + code:C9B9-6D04 + cheat + description:Clock runs faster + code:FB83-0D64 + cheat + description:Clock runs slower + code:1083-0D64 + cheat + description:Clock runs much slower + code:A683-0D64 + cheat + description:Clock is frozen (no time limit) + code:DD83-0704 + cheat + description:Food items never earn extra credit + code:3C2B-A460 + cheat + description:Double harpoon pick-up gives you machine gun + code:D184-ADA8 + cheat + description:Retain weapon after dying or advancing thru stages + code:C96E-6FD6 + cheat + description:Panic mode has 2 levels instead of 99 + code:D780-DDD4+D781-DF04 + cheat + description:Panic mode has 5 levels + code:D180-DDD4+D181-DF04 + cheat + description:Panic mode has 10 levels + code:D880-DDD4+D881-DF04 + cheat + description:Panic mode has 20 levels + code:F980-DDD4+F981-DF04 + cheat + description:Extra credit after 2 food items instead of 10 + code:D42B-A7D0 + cheat + description:Extra credit after 4 food items + code:D02B-A7D0 + cheat + description:Extra credit after 6 food items + code:D12B-A7D0 + cheat + description:Extra credit after 8 food items + code:D62B-A7D0 + cheat + description:1 credit + code:DD61-0D0A + cheat + description:2 credits + code:DF61-0D0A + cheat + description:3 credits + code:D461-0D0A + cheat + description:4 credits + code:D761-0D0A + cheat + description:6 credits + code:D961-0D0A + cheat + description:8 credits + code:D561-0D0A + cheat + description:No credits + code:EE61-0D0A + cheat + description:Start with 2 lives + code:DF61-0DDA + cheat + description:Start with 3 lives + code:D461-0DDA + cheat + description:Start with 5 lives + code:D061-0DDA + cheat + description:Start with 6 lives + code:D961-0DDA + cheat + description:Start with 8 lives + code:D561-0DDA + cheat + description:Start with 10 lives + code:DB61-0DDA + cheat + description:Start with 1 life + code:DD61-0DDA + cheat + description:Invincibility + code:7E0100:05 + cheat + description:Shield always on + code:7E0134:02 + cheat + description:Normal shot + code:7E0131:00 + cheat + description:Double shot + code:7E0131:02 + cheat + description:Grappling shot + code:7E0131:04 + cheat + description:Gun shot + code:7E0131:06 + +cartridge sha256:d42f8c7969b4c434f9ca04ce0080d897877a5e71c2926d309ef5dae93ba25548 + title:Super Caesars Palace (USA) + cheat + description:Infinite 999 gold chips + code:7E188E:E7+7E188F:03 + cheat + description:Access all high roller areas + code:7E0C30:0F + +cartridge sha256:0ef6f4cce5a2273fa49fe1ce724e0048a8e39c91da6b00dbb693fe1ba909177d + title:Super Castlevania IV (USA) + cheat + description:Invincibility + code:2D2B-6764+2DCD-D764 + cheat + description:Invincibility (blinking) + code:608E-D7FB+C92C-6DD4 + cheat + description:Infinite health + code:C22F-07D7 + cheat + description:Infinite health against most enemies + code:D22F-07D7 + cheat + description:Infinite lives (disable to get password) + code:DD6C-DD66 + cheat + description:Infinite time + code:6D6D-DF06 + cheat + description:Infinite lives + code:C96C-DFD6 + cheat + description:Infinite shots for most weapons + code:A689-0FD7 + cheat + description:Hit anywhere (cannot use whip to grab onto things, press Y to moon jump instead) + code:B428-AFA4+C728-A4D4+DD2C-A764+6D20-A7A4+6D21-AF64 + cheat + description:Fully powered whip with first power-up + code:DD24-AFD7 + cheat + description:Increase heart capacity 2.5 times + code:EE2B-6DA7+FC25-64D7+EE26-6767 + cheat + description:Max hearts on pick-up + code:DD2B-6D07 + cheat + description:Double Shot gives you a Triple Shot + code:EE2B-A767 + cheat + description:Slower timer + code:5E6D-DDA6 + cheat + description:Faster timer + code:FE6D-DDA6 + cheat + description:Super-jump + code:FDC5-04D4 + cheat + description:Mega-jump + code:4DC5-04D4 + cheat + description:Multi-jump + code:C72B-6FA4+DD2B-64D4+3C2B-6404+186D-DDD6+C28A-A46F+18CF-6D0D+462B-6D04+DC2B-6D64+BD2B-6DA4+D02B-6FD4+442B-6F04+B42B-6F64 + cheat + description:Start with and always keep Dagger + code:CBAA-6DAF+DFAA-6FDF+69AA-6F6F + cheat + description:Start with and always keep Axe + code:CBAA-6DAF+D4AA-6FDF+69AA-6F6F + cheat + description:Start with and always keep Holy Water + code:CBAA-6DAF+D7AA-6FDF+69AA-6F6F + cheat + description:Start with and always keep Boomerang + code:CBAA-6DAF+D0AA-6FDF+69AA-6F6F + cheat + description:Start with and always keep Stopwatch + code:CBAA-6DAF+D9AA-6FDF+69AA-6F6F + cheat + description:Start with 99 hearts - first life only + code:BBB3-D40F + cheat + description:Start with 50 hearts - first life only + code:9DB3-D40F + cheat + description:Start with 10 lives - first game only + code:FDB2-D4AF + cheat + description:Start with 1 life - first game only + code:DFB2-D4AF + cheat + description:Invincibility (blinking) (alt) + code:7E00BC:0A + cheat + description:Infinite health (alt) + code:7E13F4:10 + cheat + description:Infinite time (alt) + code:7E13F0:99 + cheat + description:Infinite hearts + code:7E13F2:99 + cheat + description:Have best whip + code:7E0092:02 + cheat + description:Have Dagger + code:7E008E:01 + cheat + description:Have Axe + code:7E008E:02 + cheat + description:Have Cross + code:7E008E:04 + cheat + description:Have Dagger + code:7E008E:01 + cheat + description:Have Holy Water + code:7E008E:03 + cheat + description:Have Stopwatch + code:7E008E:05 + cheat + description:Have Triple Shot + code:7E0090:02 + cheat + description:Start on second playthrough difficulty level + code:7E0088:01 + +cartridge sha256:b839253b878821ff00847491d11452e933baaf303f49dd39d22e3a524ea1ff81 + title:Super Chase H.Q. (USA) + cheat + description:Infinite health + code:7E127C:FF + cheat + description:Infinite nitro + code:7E1267:03 + cheat + description:Infinite time + code:7E127B:89 + +cartridge sha256:48afb82875ed4309f871f6b14021aa82c026fb14dc8acdbcf35f71ee605771b5 + title:Super Donkey Kong 2 - Dixie & Diddy (Japan) + cheat + description:Invincibility + code:4022-431D + +cartridge sha256:bcced1be76ef920b562a555696bcb4583d1c8cea4d4b057cab6e0e09be8ef8c4 + title:Super Double Dragon (USA) + cheat + description:Invincibility - both players + code:1D6F-0766 + cheat + description:Invincibility - P1 + code:C267-0DD6 + cheat + description:Infinite lives - P1 + code:C286-6F05 + cheat + description:Infinite lives - P1 (alt) + code:4A86-6F05 + cheat + description:Dragon power increases faster + code:DDB3-A7F1 + cheat + description:Prolonged maximum dragon power + code:D7B2-A7B5 + cheat + description:1 extra credit - 2P game A + code:DF8C-070B + cheat + description:9 lives - 1P game + code:DB86-070B + cheat + description:6 lives - 1P game + code:D186-070B + cheat + description:1 life - 1P game + code:DF86-070B + cheat + description:9 lives - 2P game A + code:DB88-0D6B + cheat + description:6 lives - 2P game A + code:D188-0D6B + cheat + description:1 life - 2P game A + code:DF88-0D6B + cheat + description:Start on Mission 2 (enable on Mode Seclect screen, then disable) + code:7E001C:14 + cheat + description:Start on Mission 3 (enable on Mode Seclect screen, then disable) + code:7E001C:17 + cheat + description:Start on Mission 4 (enable on Mode Seclect screen, then disable) + code:7E001C:1C + cheat + description:Start on Mission 5 (enable on Mode Seclect screen, then disable) + code:7E001C:1D + cheat + description:Start on Mission 6 (enable on Mode Seclect screen, then disable) + code:7E001C:1F + cheat + description:Start on Mission 7 (enable on Mode Seclect screen, then disable) + code:7E001C:20 + +cartridge sha256:7468c271d7240cf4e0d08c16e9969a1b1b1caf5adc0e5adc568d93c92651a057 + title:Super Ghouls'n Ghosts (USA) + cheat + description:Invincibility (disable at end of first two stages of level 3, so you can trigger the hidden end of stage marker) + code:D4D5-B286 + cheat + description:Invincibility (alt) + code:DD21-0FD0 + cheat + description:Never lose Armor + code:DFD0-F38B+DFF8-F38B + cheat + description:Infinite time + code:A286-0F01 + cheat + description:Infinite lives + code:A2C1-AD01 + cheat + description:Infinite double-jumps + code:C2A5-A4A5 + cheat + description:Infinite shield hits + code:6DE7-A468 + cheat + description:Infinite continues + code:DDB6-67FF + cheat + description:Very few Zombies appear + code:C9BB-A460 + cheat + description:Most Zombies carry a basket + code:DF65-DFA8+CBBD-AF98 + cheat + description:Slower timer + code:9386-0D01 + cheat + description:Faster timer + code:FE86-0D01 + cheat + description:Start with 9 minutes + code:DBC3-0465 + cheat + description:Start with 1 continue + code:DFC0-A401 + cheat + description:Start with 9 continues + code:DBC0-A401 + cheat + description:Invincibility (alt 2) + code:7E0276:02 + cheat + description:Never lose Armor (alt) + code:7E044A:01+7E14BA:01 + cheat + description:Infinite time (alt) + code:7E02A9:01 + cheat + description:Infinite lives (alt) + code:7E02A4:02 + cheat + description:Infinite double-jumps (alt) + code:7E14BC:00 + cheat + description:Super-jump + code:7E0458:0F + cheat + description:Run faster + code:7E0453:02 + cheat + description:900,000 points + code:7E0295:09 + cheat + description:Have no Armor + code:7E14BA:00 + cheat + description:Have regular Armor + code:7E14BA:01 + cheat + description:Have Green Armor + code:7E14BA:02 + cheat + description:Have Gold Armor + code:7E14BA:04 + cheat + description:Have Javelin + code:7E14D3:00 + cheat + description:Have Blue Fire Javelin + code:7E14D3:01 + cheat + description:Have Quick Dagger + code:7E14D3:02 + cheat + description:Have Laser Dagger + code:7E14D3:03 + cheat + description:Have Crossbow + code:7E14D3:04 + cheat + description:Have Crossbow with Homing Arrows + code:7E14D3:05 + cheat + description:Have Scythe + code:7E14D3:06 + cheat + description:Have Scythe level 2 + code:7E14D3:07 + cheat + description:Have Torch + code:7E14D3:08 + cheat + description:Have Torch level 2 + code:7E14D3:09 + cheat + description:Have Axe + code:7E14D3:0A + cheat + description:Have Double Edge Axe + code:7E14D3:0B + cheat + description:Have Dagger with L-shaped path + code:7E14D3:0C + cheat + description:Have Shuriken with L-shaped path + code:7E14D3:0D + cheat + description:Have Goddess Ring + code:7E14D3:0E + +cartridge sha256:3f8efb19eae68f24feb42c018b7dc7a819bfd8d993ab36899681caa7ee94b06e + title:Super James Pond (USA) + cheat + description:Infinite health + code:7EB130:03 + cheat + description:Infinite lives + code:7EB12E:03 + +cartridge sha256:a9e3e57d591e995e8e0dd228b619b6aed42205eaf55316fa8ff33f236b3a32b3 + title:Super Mario All-Stars (USA) + cheat + description:SMB - Invincibility (Starman effect) + code:292B-67DE + cheat + description:SMB - Invincibility does not last as long + code:D62F-6DAE + cheat + description:SMB - Invincibility lasts longer + code:9D2F-6DAE + cheat + description:SMB - Infinite lives (alt) + code:C2C1-D4AA + cheat + description:SMB - Infinite time + code:6D84-DF03 + cheat + description:SMB - Multi-jump + code:2D8E-D7D2 + cheat + description:SMB - Run without holding the dash button + code:DD8E-D702 + cheat + description:SMB - Start File A game with 2 lives + code:DFDF-FAAD + cheat + description:SMB - Start File A game with 10 lives + code:DBDF-FAAD + cheat + description:SMB - Start File A game with 50 lives + code:7FDF-FAAD + cheat + description:SMB - Start File A game with 100 lives + code:17DF-FAAD + cheat + description:SMB - 1-up worth nothing + code:C26B-0FBF + cheat + description:SMB - Allows you to select any world for File A + code:D5DF-FADD + cheat + description:SMB - Jump lower (disable if you get stuck) + code:CB81-0D02+E281-0D62+3C81-0DA2 + cheat + description:SMB - Super-jump + code:CB81-0D02+EC81-0D62+3C81-0DA2 + cheat + description:SMB - Mega-jump + code:CB81-0D02+E681-0D62+3C81-0DA2 + cheat + description:LL - Start File A game with 2 lives + code:DFDF-FEDD + cheat + description:LL - Start File A game with 10 lives + code:DBDF-FEDD + cheat + description:LL - Start File A game with 50 lives + code:7FDF-FEDD + cheat + description:LL - Start File A game with 100 lives + code:17DF-FEDD + cheat + description:LL - Infinite lives + code:C2B6-A455 + cheat + description:LL - Infinite time + code:6D82-0F79 + cheat + description:LL - Allows you to select any world or level for File A + code:DADF-F30D+D7DF-F36D + cheat + description:LL - Infinite lives + code:C2B6-A455 + cheat + description:LL - Multi-jump + code:DD86-6F80 + cheat + description:SMB2 - Multi-jump - all characters + code:D966-6166 + cheat + description:SMB2 - Float - all characters + code:6267-A5A6 + cheat + description:SMB2 - 1 life after continue + code:DF61-05D0 + cheat + description:SMB2 - 9 lives after continue + code:DB61-05D0 + cheat + description:SMB2 - 25 lives after continue + code:FB61-05D0 + cheat + description:SMB2 - 50 lives after continue + code:7461-05D0 + cheat + description:SMB2 - 99 lives after continue + code:1761-05D0 + cheat + description:SMB2 - Infinite lives + code:C26E-D5A6 + cheat + description:SMB2 - Continue with 3 hearts instead of 2 + code:DF6B-A9A1 + cheat + description:SMB2 - Continue with 4 hearts + code:D46B-A9A1 + cheat + description:SMB2 - Infinite hearts + code:DD32-6966 + cheat + description:SMB2 - Jumping in place charges super jump + code:7A60-A966 + cheat + description:SMB2 - Allows you to select any world for File A + code:D1D4-FA0D + cheat + description:SMB3 - Infinite lives + code:82BB-0C6D + cheat + description:SMB3 - Infinite time + code:6D3D-6619 + cheat + description:SMB3 - Infinite flying time + code:EEA4-AB63 + cheat + description:SMB3 - Multi-jump + code:40AA-6803 + cheat + description:SMB3 - Fly at any time (run meter always full) + code:DDAF-A8A3 + cheat + description:SMB3 - Fireballs hit anywhere + code:4083-D8F3+408D-08F3 + cheat + description:SMB3 - Tail hits anywhere + code:40C4-6C22 + cheat + description:SMB3 - Fireballs can kill most enemies + code:4084-0BB3 + cheat + description:SMB3 - Change to Big Mario whenever you go to the map + code:CB69-AC07+DF69-AC67 + cheat + description:SMB3 - Change to Fire Mario whenever you go to the map + code:CB69-AC07+D469-AC67 + cheat + description:SMB3 - Change to Raccoon Mario whenever you go to the map + code:CB69-AC07+D769-AC67 + cheat + description:SMB3 - Change to Frog Mario whenever you go to the map + code:CB69-AC07+D069-AC67 + cheat + description:SMB3 - Change to Tanooki Mario whenever you go to the map + code:CB69-AC07+D969-AC67 + cheat + description:SMB3 - Change to Sledgehammer Mario when you go to the map + code:CB69-AC07+D169-AC67 + cheat + description:SMB3 - All power-ups turn you into Shoe Mario + code:D0A1-6C0A+E1A3-D60A + cheat + description:SMB3 - Collisions turn you into Big Mario + code:D4A8-6CAA + cheat + description:SMB3 - Collisions turn you into Fire Mario + code:D7A8-6CAA + cheat + description:SMB3 - Collisions turn you into Raccoon Mario + code:D0A8-6CAA + cheat + description:SMB3 - Collisions turn you into Frog Mario + code:D9A8-6CAA + cheat + description:SMB3 - Collisions turn you into Tanooki Mario + code:D1A8-6CAA + cheat + description:SMB3 - Collisions turn you into Sledgehammer Mario + code:D5A8-6CAA + cheat + description:SMB3 - After getting star, invincible until end of level (may have to disable to jump) + code:C23B-680D + cheat + description:SMB3 - 1 life after continue + code:DFBB-DBAF + cheat + description:SMB3 - 10 lives after continue + code:DBBB-DBAF + cheat + description:SMB3 - 26 lives after continue + code:FBBB-DBAF + cheat + description:SMB3 - 51 lives after continue + code:74BB-DBAF + cheat + description:SMB3 - 100 lives after continue + code:17BB-DBAF + cheat + description:SMB3 - Gain lots of lives with each 5 coins + code:D93E-6C49 + cheat + description:SMB3 - 5 coins needed for an extra life + code:D93E-6819 + cheat + description:SMB3 - 10 coins needed for an extra life + code:DC3E-6819 + cheat + description:SMB3 - 25 coins needed for an extra life + code:FB3E-6819 + cheat + description:SMB3 - 50 coins needed for an extra life + code:743E-6819 + cheat + description:SMB3 - Power-jump + code:AD3E-6801 + cheat + description:SMB3 - Super-jump + code:863E-6801 + cheat + description:SMB3 - Mega-jump + code:8D3E-6801 + cheat + description:SMB3 - Ultra power-jump + code:C63E-6801 + cheat + description:SMB3 - Mega power-jump + code:DDA9-A603 + cheat + description:SMB3 - Select any world for File A game + code:D5D4-F36D + cheat + description:SMB3 - Re-enter already beaten levels + code:DD63-D6A5 + cheat + description:SMB3 - Re-enter already beaten fortresses + code:1D63-D665 + cheat + description:SMB3 - Re-enter already beaten mushroom houses and special levels + code:0D63-D605 + cheat + description:SMB3 - Start and continue as Big Mario + code:E1A3-D60A + cheat + description:SMB - Invincibility (Starman) + code:7E07AF:0F + cheat + description:SMB - Infinite lives + code:7E075A:05 + cheat + description:SMB2 - Invincibility + code:7E0085:3B + cheat + description:SMB2 - Always big + code:7E04C3:1F + cheat + description:SMB2 - Always small + code:7E04C3:0F + cheat + description:SMB2 - Infinite float time - all characters + code:7E04CA:FF + cheat + description:SMB3 - Enable debug mode (in game) + code:7E0160:80 + cheat + description:SMB3 - Invincibility + code:7E0552:80 + cheat + description:SMB3 - Invincibility (Starman) + code:7E0553:FF + cheat + description:SMB3 - Always Small Mario + code:7E00BB:00 + cheat + description:SMB3 - Always Big Mario + code:7E00BB:01 + cheat + description:SMB3 - Always Fire Mario + code:7E00BB:02 + cheat + description:SMB3 - Always Raccoon Mario + code:7E00BB:03 + cheat + description:SMB3 - Always Frog Mario + code:7E00BB:04 + cheat + description:SMB3 - Always Tanooki Mario + code:7E00BB:05 + cheat + description:SMB3 - Always Hammer Bros. Mario + code:7E00BB:06 + cheat + description:SMB3 - Have Magic Whistle + code:7E1D80:0C + cheat + description:SMB3 - Raccoon and Tanooki have P-Wing + code:7E056E:FF + cheat + description:SMB3 - Fly for an unlimited amount of time + code:23CB26:FF + +cartridge sha256:a8806bfe07cd3c9945d9fd3fcea932ae1cd671cab5cae12bb7a2ae726cbf9175 + title:Super Mario All-Stars + Super Mario World (USA) + cheat + description:SMB - Invincibility (Starman effect) + code:292B-67DE + cheat + description:SMB - Invincibility + code:62E7-A7D2+2DE7-A7A2 + cheat + description:SMB - Always Fiery Mario after first hit + code:CB29-AF0E+D429-AF6E+CB8B-676A+DD8B-67AA + cheat + description:SMB - Fireballs hit anywhere + code:4028-D4DE + cheat + description:SMB - Multi-jump + code:2D8E-D7D2 + cheat + description:SMB - Run without holding the dash button + code:DD8E-D702 + cheat + description:LL - Infinite lives + code:C2B6-A455 + cheat + description:LL - Multi-jump + code:DD86-6F80 + cheat + description:SMB2 - Infinite lives + code:C26E-D5A6 + cheat + description:SMB2 - Infinite hearts + code:DD32-6966 + cheat + description:SMB2 - Multi-jump - all characters + code:D966-6166 + cheat + description:SMB2 - Float - all characters + code:6267-A5A6 + cheat + description:SMB3 - Fireballs hit anywhere + code:4083-D8F3+408D-08F3 + cheat + description:SMB3 - Tail hits anywhere + code:40C4-6C22 + cheat + description:SMB3 - Fireballs can kill most enemies + code:4084-0BB3 + cheat + description:SMB3 - Re-enter already beaten levels + code:DD63-D6A5 + cheat + description:SMB3 - Re-enter already beaten fortresses + code:1D63-D665 + cheat + description:SMB3 - Re-enter already beaten mushroom houses and special levels + code:0D63-D605 + cheat + description:SMW - Nintendo's debug + code:DDA6-DF07 + cheat + description:SMW - Infinite flying time for Yoshi + code:C2EC-0700 + cheat + description:SMB - Invincibility (Starman) + code:7E07AF:0F + cheat + description:SMB - Infinite lives + code:7E075A:05 + cheat + description:SMB2 - Invincibility + code:7E0085:3B + cheat + description:SMB2 - Infinite float time - all characters + code:7E04CA:FF + cheat + description:SMB3 - Enable debug mode (in game) + code:7E0160:80 + cheat + description:SMB3 - Infinite lives + code:20919A:BD + cheat + description:SMB3 - Invincibility + code:7E0552:80 + cheat + description:SMB3 - Invincibility (Starman) + code:7E0553:FF + cheat + description:SMB3 - Always Small Mario + code:7E00BB:00 + cheat + description:SMB3 - Always Big Mario + code:7E00BB:01 + cheat + description:SMB3 - Always Fire Mario + code:7E00BB:02 + cheat + description:SMB3 - Always Raccoon Mario + code:7E00BB:03 + cheat + description:SMB3 - Always Frog Mario + code:7E00BB:04 + cheat + description:SMB3 - Always Tanooki Mario + code:7E00BB:05 + cheat + description:SMB3 - Always Hammer Bros Mario + code:7E00BB:06 + cheat + description:SMB3 - Infinite flying time + code:23CB26:FF + cheat + description:SMB3 - Have Magic Whistle + code:7E1D80:0C + cheat + description:SMB3 - Raccoon and Tanooki have P-Wing + code:7E056E:FF + cheat + description:SMW - Invincibility + code:7E1497:FF + cheat + description:SMW - Invincible (Starman) + code:7E1490:FF + cheat + description:SMW - Always Small Mario + code:7E0019:00 + cheat + description:SMW - Always Big Mario + code:7E0019:01 + cheat + description:SMW - Always Caped Mario + code:7E0019:02 + cheat + description:SMW - Always Fire Mario + code:7E0019:03 + cheat + description:SMW - Infinite time + code:7E0F31:09+7E0F32:09+7E0F33:09 + cheat + description:SMW - Infinite P-Balloon time + code:7E1891:FF + cheat + description:SMW - Always have Yoshi + code:7E0DC1:01 + cheat + description:SMW - Jump to automatically fly + code:7E13E4:70 + cheat + description:SMW - Multi-jump and float down (disable in water and to get on Yoshi) + code:7E1471:01 + cheat + description:SMW - Activate yellow blocks (deactivate before entering the Yellow Switch Palace) + code:7E1F28:01 + cheat + description:SMW - Activate blue blocks (deactivate before entering the Blue Switch Palace) + code:7E1F29:01 + cheat + description:SMW - Activate red blocks (deactivate before entering the Red Switch Palace) + code:7E1F2A:01 + cheat + description:SMW - 8000 points for each enemy stomped + code:7E1697:06 + +cartridge sha256:2ada8919688087be60a6a48cace8f877add60c45d2e5d09e2442faa55be62a49 + title:Super Mario Kart (USA) + cheat + description:Invincibility + code:1A3E-CDA4 + cheat + description:All karts except yours do not move + code:9980-44DD + cheat + description:Drive through walls + code:4FEB-CDA4 + cheat + description:Drive through opponents + code:97A6-CDAD + cheat + description:Invincibility and have a Red Shell + code:7E0D70:28 + cheat + description:Always have Red Shell + code:7E0D70:05 + cheat + description:Always have item + code:7E0D71:C0 + cheat + description:Drive anywhere + code:80FA93:20 + cheat + description:Mud and other land doesn't effect driving + code:759DC8:B4 + cheat + description:Special Cup enabled (1P time trial and 2P match race) + code:7E1D29:03 + +cartridge sha256:740646f3535bfb365ca44e70d46ab433467b142bd84010393070bd0b141af853 + title:Super Mario RPG - Legend of the Seven Stars (USA) + cheat + description:Infinite tries in action sequences + code:A98E-7707 + cheat + description:Infinite HP - Character 1 + code:7EFA91:FF + cheat + description:Infinite HP - Character 2 + code:7EFB11:FF + cheat + description:Infinite HP - Character 3 + code:7EFB91:FF + cheat + description:Max HP - Character 1 + code:7EFA93:FF + cheat + description:Max HP - Character 2 + code:7EFB13:FF + cheat + description:Max HP - Character 3 + code:7EFB93:FF + cheat + description:Max Flower Points + code:7EFA0D:63 + cheat + description:Infinite Flower Points (In Battle) + code:7EFA0D:63+7EFA0C:63 + cheat + description:Infinite Coins + code:7FF8AF:E7+7FF8B0:03 + cheat + description:Infinite Frog Coins + code:7FF8B3:E7+7FF8B4:03 + cheat + description:255 EXP per battle (disable before going to the World Map or using the menu button) + code:7EFA02:FF + cheat + description:Always Mario's turn + code:7E0702:00 + cheat + description:Mario consecutive super jumps modifier + code:7FF8C0:64 + cheat + description:Mario - Level 30 + code:7FF800:1E + cheat + description:Mario - 999 HP + code:7FF801:E7+7FF802:03 + cheat + description:Mario - 999 Max HP + code:7FF803:E7+7FF804:03 + cheat + description:Mario - Max Speed + code:7FF805:FF + cheat + description:Mario - Max Attack + code:7FF806:FF + cheat + description:Mario - Max Defense + code:7FF807:FF + cheat + description:Mario - Max Magic Attack + code:7FF808:FF + cheat + description:Mario - Max Magic Defense + code:7FF809:FF + cheat + description:Mario - Max Experience + code:7FF80A:0F+7FF80B:27 + cheat + description:Mario - Equipped Weapon + code:7FF80C:1C + cheat + description:Mario - Equipped Armor + code:7FF80D:46 + cheat + description:Mario - Equipped Accessory + code:7FF80E:5E + cheat + description:Mario - Has all 'Correct' Spells + code:7FF810:3F + cheat + description:Mallow - Level 30 + code:7FF850:1E + cheat + description:Mallow - 999 HP + code:7FF851:E7+7FF852:03 + cheat + description:Mallow - 999 Max HP + code:7FF853:E7+7FF854:03 + cheat + description:Mallow - Max Speed + code:7FF855:FF + cheat + description:Mallow - Max Attack + code:7FF856:FF + cheat + description:Mallow - Max Defense + code:7FF857:FF + cheat + description:Mallow - Max Magic Attack + code:7FF858:FF + cheat + description:Mallow - Max Magic Defense + code:7FF859:FF + cheat + description:Mallow - Max Experience + code:7FF85A:0F+7FF85B:27 + cheat + description:Mallow - Equipped Weapon + code:7FF85C:20 + cheat + description:Mallow - Equipped Armor + code:7FF85D:46 + cheat + description:Mallow - Equipped Accessory + code:7FF85E:5E + cheat + description:Mallow - has all 'correct' spells + code:7FF862:E0+7FF863:07 + cheat + description:Geno - Level 30 + code:7FF83C:1E + cheat + description:Geno - 999 HP + code:7FF83D:E7+7FF83E:03 + cheat + description:Geno - 999 Max HP + code:7FF83F:E7+7FF840:03 + cheat + description:Geno - Max Speed + code:7FF841:FF + cheat + description:Geno - Max Attack + code:7FF842:FF + cheat + description:Geno - Max Defense + code:7FF843:FF + cheat + description:Geno - Max Magic Attack + code:7FF844:FF + cheat + description:Geno - Max Magic Defense + code:7FF845:FF + cheat + description:Geno - Max Experience + code:7FF846:0F+7FF847:27 + cheat + description:Geno - Equipped Weapon + code:7FF848:1F + cheat + description:Geno - Equipped Armor + code:7FF849:46 + cheat + description:Geno - Equipped Accessory + code:7FF84A:5E + cheat + description:Geno - Has all 'correct' spells + code:7FF84E:1F + cheat + description:Bowser - Level 30 + code:7FF828:1E + cheat + description:Bowser - 999 HP + code:7FF829:E7+7FF82A:03 + cheat + description:Bowser - 999 Max HP + code:7FF82B:E7+7FF82C:03 + cheat + description:Bowser - Max Speed + code:7FF82D:FF + cheat + description:Bowser - Max Attack + code:7FF82E:FF + cheat + description:Bowser - Max Defense + code:7FF82F:FF + cheat + description:Bowser - Max Magic Attack + code:7FF830:FF + cheat + description:Bowser - Max Magic Defense + code:7FF831:FF + cheat + description:Bowser - Max Experience + code:7FF832:0F+7FF833:27 + cheat + description:Bowser - Equipped Weapon + code:7FF834:1E + cheat + description:Bowser - Equipped Armor + code:7FF835:46 + cheat + description:Bowser - Equipped Accessory + code:7FF836:5E + cheat + description:Bowser - Has all 'correct' spells + code:7FF839:F0 + cheat + description:Princess - Level 30 + code:7FF814:1E + cheat + description:Princess - 999 HP + code:7FF815:E7+7FF816:03 + cheat + description:Princess - 999 Max HP + code:7FF817:E7+7FF818:03 + cheat + description:Princess - Max Speed + code:7FF819:FF + cheat + description:Princess - Max Attack + code:7FF81A:FF + cheat + description:Princess - Max Defense + code:7FF81B:FF + cheat + description:Princess - Max Magic Attack + code:7FF81C:FF + cheat + description:Princess - Max Magic Defense + code:7FF81D:FF + cheat + description:Princess - Max Experience + code:7FF81E:0F+7FF81F:27 + cheat + description:Princess - Equipped Weapon + code:7FF820:22 + cheat + description:Princess - Equipped Armor + code:7FF821:46 + cheat + description:Princess - Equipped Accessory + code:7FF822:5E + cheat + description:Princess - Has all 'correct' spells + code:7FF824:C0+7FF825:0F + +cartridge sha256:0838e531fe22c077528febe14cb3ff7c492f1f5fa8de354192bdff7137c27f5b + title:Super Mario World (USA) + cheat + description:Start and stay invincible most of the time + code:DD32-6DAD + cheat + description:Invincibility for Yoshi + code:89E4-AFD9+89C6-D4DB + cheat + description:Infinite flying time for Yoshi + code:C2EC-0700 + cheat + description:Infinite time (disable for puzzles that use the timer) + code:C264-64D7 + cheat + description:Infinite lives + code:C222-D4DD + cheat + description:Cape hits anywhere + code:40BE-AD66 + cheat + description:Fireballs hit anywhere + code:40C2-D7A6 + cheat + description:Fireballs shoot straight + code:DDEA-6F07+DDB2-AFD8 + cheat + description:Fireballs turn most enemies into Flowers + code:59C4-0466 + cheat + description:Fireballs turn most enemies into 1-Up Mushrooms + code:56C4-0466 + cheat + description:Fireballs turn most enemies into Starmen + code:51C4-0466 + cheat + description:Multi-jump + code:6D2E-0FDF + cheat + description:Spin jump in mid air (hold for float down) + code:F53F-6767+DD3F-67A7 + cheat + description:Low jump + code:D02C-AF6F + cheat + description:Super-jump + code:D42C-AF6F + cheat + description:Mega-jump + code:DF2C-AF6F + cheat + description:Little Yoshi grows after eating 1 enemy instead of 5 + code:DFCE-64A0 + cheat + description:Little Yoshi grows after eating 2 enemies + code:D4CE-64A0 + cheat + description:Little Yoshi grows after eating 3 enemies + code:D7CE-64A0 + cheat + description:Little Yoshi grows after eating 4 enemies + code:D0CE-64A0 + cheat + description:Nintendo's Debug + code:DDC1-64DD+DDC5-6DAD + cheat + description:Nintendo's Debug 2 + code:DDA6-DF07 + cheat + description:1-Up at 5 coins instead of 100 + code:D964-A7D7+D967-AFA7 + cheat + description:1-Up at 10 coins + code:DC64-A7D7+DC67-AFA7 + cheat + description:1-Up at 20 coins + code:F064-A7D7+F067-AFA7 + cheat + description:1-Up at 50 coins + code:7464-A7D7+7467-AFA7 + cheat + description:1-Up at 1 dragon coin instead of 5 + code:D2E5-A7AD + cheat + description:Start as Super Mario + code:31B7-6F07 + cheat + description:Start as Cape Mario + code:CBB7-6D67+D4B7-6DA7+3CB7-6FD7+69B7-6F07 + cheat + description:Start as Fire Mario + code:CBB7-6D67+D7B7-6DA7+3CB7-6FD7+69B7-6F07 + cheat + description:Start with 1 life instead of 5 + code:DDB4-6F07 + cheat + description:Start with 9 lives + code:D6B4-6F07 + cheat + description:Start with 15 lives + code:D3B4-6F07 + cheat + description:Start with 25 lives + code:F6B4-6F07 + cheat + description:Start with 50 lives + code:7FB4-6F07 + cheat + description:Start with 99 lives + code:14B4-6F07 + cheat + description:Invincibility + code:7E1497:FF + cheat + description:Invincibility (Starman) + code:7E1490:FF + cheat + description:Infinite P-Balloon time + code:7E1891:FF + cheat + description:Always Small Mario + code:7E0019:00 + cheat + description:Always Big Mario + code:7E0019:01 + cheat + description:Always Caped Mario + code:7E0019:02 + cheat + description:Always Fiery Mario + code:7E0019:03 + cheat + description:Always have Yoshi + code:7E0DC1:01 + cheat + description:Multi-jump and float down (disable in water and to get on Yoshi) + code:7E1471:01 + cheat + description:Activate green blocks (disable before entering the Green Switch Palace) + code:7E1F27:01 + cheat + description:Activate yellow blocks (disable before entering the Yellow Switch Palace) + code:7E1F28:01 + cheat + description:Activate red blocks (disable before entering the Red Switch Palace) + code:7E1F2A:01 + cheat + description:Activate blue blocks (disable before entering the Blue Switch Palace) + code:7E1F29:01 + cheat + description:8000 points for each enemy stomped + code:7E1697:06 + cheat + description:Reznor already defeated in all four fortresses + code:7E1520:01+7E1521:01+7E1522:01+7E1523:01 + +cartridge sha256:bd763c1a56365c244be92e6cffefd318780a2a19eda7d5baf1c6d5bd6c1b3e06 + title:Super Mario World 2 - Yoshi's Island (USA) (Rev 1) + cheat + description:Infinite lives + code:C2EE-649F + cheat + description:All levels are completed with 100 points + code:CB69-006D+3069-00AD + cheat + description:Always score 100 points + code:CB8A-64D5+108A-6405+3C8A-6465 + cheat + description:Power-ups don't get used up + code:1D26-AFA1 + cheat + description:Mario's crying disabled + code:44A0-672B + cheat + description:Horizontal one-way pinball doors open from both sides + code:6DB6-6F55 + cheat + description:Infinite lives/Start at Middle Ring (when you die) + code:C2EE-64BF + cheat + description:After using the magnifying glass, red coins and hidden items are always revealed + code:C2C8-A465 + cheat + description:Red switches stay on for over twice as long + code:D98A-AF7B + cheat + description:Red switches stay on for over four times as long + code:DB8A-AF7B + cheat + description:Red switches stay on for a very, very long time + code:5E8A-AF7B + cheat + description:Disable autoscroll + code:C220-D4D3 + cheat + description:Don't get crushed + code:18CB-D727 + cheat + description:Multi-jump + code:D921-D496+C421-D4B6+E821-D426+6321-D7F6+C821-D796+1D21-D7B6+5421-DD26+1D21-DFF6+4B21-DF96+DD21-DFB6+6D21-DF26+ED21-D4F6 + cheat + description:Star timer doesn't decrease when hit + code:7E0391:01+7E0392:00 + cheat + description:Mario's crying disabled (alt) + code:06C64F:22 + cheat + description:Infinite red switch time + code:7E0CEC:66 + cheat + description:Hold B to float + code:7E0945:00 + cheat + description:Unlock items in boss fights + code:7E0B48:00 + cheat + description:Have Stars +10 + code:7E0357:01 + cheat + description:Have Stars +20 + code:7E0358:02 + cheat + description:Have POW Block + code:7E0359:03 + cheat + description:Have full Eggs + code:7E035A:04 + cheat + description:Have Magnifying Glass + code:7E035B:05 + cheat + description:Have Winged Cloud + code:7E035C:06 + cheat + description:Have Green Watermelon + code:7E035D:07 + cheat + description:Have Blue Watermelon + code:7E035E:08 + cheat + description:Have Red Watermelon + code:7E035F:09 + cheat + description:Have Pink Yoshi + code:7E0383:01 + cheat + description:Have Orange Yoshi + code:7E0383:02 + cheat + description:Have Light Blue Yoshi + code:7E0383:03 + cheat + description:Have Purple Yoshi + code:7E0383:04 + cheat + description:Have Brown Yoshi + code:7E0383:05 + cheat + description:Have Red Yoshi + code:7E0383:06 + cheat + description:Have Dark Blue Yoshi + code:7E0383:07 + cheat + description:Have Glow Red Yoshi + code:7E0383:08 + cheat + description:Have Shadow Yoshi + code:7E0383:09 + +cartridge sha256:9b4957466798bbdb5b43a450bbb60b2591ae81d95b891430f62d53ca62e8bc7b + title:Super Mario World 2 - Yoshi's Island (USA) + cheat + description:Infinite lives + code:C2EE-649F + cheat + description:Infinite lives and start at middle ring when you die + code:C2EE-64BF + cheat + description:All levels are completed with 100 points + code:CB69-006D+3069-00AD + cheat + description:Always score 100 points + code:CB8A-64D5+108A-6405+3C8A-6465 + cheat + description:Power-ups don't get used up + code:1D26-AFA1 + cheat + description:Mario's crying disabled + code:44A0-672B + cheat + description:Horizontal one-way pinball doors open from both sides + code:6DB6-6F55 + cheat + description:After using the magnifying glass, red coins and hidden items are always revealed + code:C2C8-A465 + cheat + description:Red switches stay on for over twice as long + code:D98A-AF7B + cheat + description:Red switches stay on for over four times as long + code:DB8A-AF7B + cheat + description:Disable autoscroll + code:C220-D4D3 + cheat + description:Don't get crushed + code:18CB-D727 + cheat + description:Multi-jump + code:D921-D496+C421-D4B6+E821-D426+6321-D7F6+C821-D796+1D21-D7B6+5421-DD26+1D21-DFF6+4B21-DF96+DD21-DFB6+6D21-DF26+ED21-D4F6 + cheat + description:Continue with 5 lives + code:DC36-010D + cheat + description:Continue with 10 lives + code:FB36-010D + cheat + description:Continue with 25 lives + code:7436-010D + cheat + description:Continue with 50 lives + code:1736-010D + cheat + description:Continue with 99 lives + code:1736-010D + cheat + description:Start with 5 lives + code:D9B7-0023 + cheat + description:Start with 10 lives + code:DCB7-0023 + cheat + description:Start with 25 lives + code:FBB7-0023 + cheat + description:Start with 50 lives + code:74B7-0023 + cheat + description:Start with 99 lives + code:17B7-0023 + cheat + description:Star timer doesn't decrease when hit + code:7E0391:01+7E0392:00 + cheat + description:Hold B to float + code:7E0945:00 + cheat + description:Unlock items in boss fights + code:7E0B48:00 + cheat + description:Infinite red switch time + code:7E0CEC:66 + cheat + description:Mario's crying disabled (alt) + code:06C64F:22 + cheat + description:Have Stars +10 + code:7E0357:01 + cheat + description:Have Stars +20 + code:7E0358:02 + cheat + description:Have POW Block + code:7E0359:03 + cheat + description:Have full Eggs + code:7E035A:04 + cheat + description:Have Magnifying Glass + code:7E035B:05 + cheat + description:Have Winged Cloud + code:7E035C:06 + cheat + description:Have Green Watermelon + code:7E035D:07 + cheat + description:Have Blue Watermelon + code:7E035E:08 + cheat + description:Have Red Watermelon + code:7E035F:09 + cheat + description:Have Pink Yoshi + code:7E0383:01 + cheat + description:Have Orange Yoshi + code:7E0383:02 + cheat + description:Have Light Blue Yoshi + code:7E0383:03 + cheat + description:Have Purple Yoshi + code:7E0383:04 + cheat + description:Have Brown Yoshi + code:7E0383:05 + cheat + description:Have Red Yoshi + code:7E0383:06 + cheat + description:Have Dark Blue Yoshi + code:7E0383:07 + cheat + description:Have Glow Red Yoshi + code:7E0383:08 + cheat + description:Have Shadow Yoshi + code:7E0383:09 + +cartridge sha256:12b77c4bc9c1832cee8881244659065ee1d84c70c3d29e6eaf92e6798cc2ca72 + title:Super Metroid (Japan, USA) (En,Ja) + cheat + description:Invincibility (except for acid and when bosses grab you) + code:DFFC-F37C + cheat + description:Infinite energy (except for acid) + code:C225-3005 + cheat + description:Infinite Missiles + code:C288-C5A7 + cheat + description:Infinite Super Missiles + code:C28A-C9D7 + cheat + description:Infinite Power Bombs + code:3CA4-450D + cheat + description:Infinite Power Bombs (alt) + code:17DA-9E8C + cheat + description:Super-jumps don't drain energy + code:C22A-456D + cheat + description:Enemies die on contact (Speed Booster effect) + code:6DC8-4CDF+6DCC-4BDF + cheat + description:Skip intro and start on Planet Zebes on new game + code:DD38-C4A8 + cheat + description:Select area when loading saved game A (press right on map screen) + code:DDCF-4461+6DCC-47A1 + cheat + description:Switching areas fills the map + code:CE6B-1FAF+D76B-146F + cheat + description:Automatically collect secret and/or special items in current room (Missiles, Energy Tanks, ect) + code:402B-3DB7+402E-3FF7 + cheat + description:Can access Tourain from sunken statues room + code:AF24-FA7C+FE24-FA5C + cheat + description:Full movement in Maridia sand + code:6D8F-14FF+DDBF-4504 + cheat + description:Multi-jump (when using button A) + code:C933-C9A7+6333-C1D7+DC33-C107+BD33-C167+D033-C1A7+4433-C5D7+8A33-C507+B633-C567+BD33-C5A7 + cheat + description:Multi-jump (when using button B) + code:C933-C9A7+6E33-C1D7+DC33-C107+BD33-C167+D033-C1A7+4433-C5D7+8A33-C507+B633-C567+BD33-C5A7 + cheat + description:Metroids can be killed without being frozen first + code:403F-38DE+6D34-3BAE + cheat + description:0 hours played + code:DDD0-FE6D + cheat + description:Brinstar mapped + code:EE2D-935C + cheat + description:Crateria mapped + code:EE2D-937C + cheat + description:Maridia mapped + code:EE2D-9E7C + cheat + description:Norfair mapped + code:EE2D-938C + cheat + description:Tourain mapped + code:EE2D-9E5C + cheat + description:Wrecked Ship mapped + code:EE2D-93EC + cheat + description:Maximum 99 Power Bombs + code:17D2-9A7C + cheat + description:Maximum 99 Super Missiles + code:17DA-9E7C + cheat + description:Maximum Missiles=10 + code:DCD7-F26D + cheat + description:Maximum Missiles=100 + code:10D7-F26D + cheat + description:Maximum Missiles=125 + code:52D7-F26D + cheat + description:Maximum Missiles=150 + code:B1D7-F26D + cheat + description:Maximum Missiles=175 + code:CED7-F26D + cheat + description:Maximum Missiles=200 + code:A6D7-F26D + cheat + description:Maximum Missiles=25 + code:FBD7-F26D + cheat + description:Maximum Missiles=50 + code:74D7-F26D + cheat + description:Maximum Missiles=75 + code:08D7-F26D + cheat + description:Maximum Power Bombs=10 + code:DCD7-FE6D + cheat + description:Maximum Power Bombs=25 + code:FBD7-FE6D + cheat + description:Maximum Power Bombs=5 + code:D9D7-FE6D + cheat + description:Maximum Power Bombs=50 + code:74D7-FE6D + cheat + description:Maximum Super Missiles=10 + code:DCD7-F36D + cheat + description:Maximum Super Missiles=25 + code:FBD7-F36D + cheat + description:Maximum Super Missiles=5 + code:D9D7-F36D + cheat + description:Maximum Super Missiles=50 + code:74D7-F36D + cheat + description:Start with about 500 Energy Tanks on saved game A + code:E7D7-FAAD+DFD7-FA6D + cheat + description:Start with about 700 Energy Tanks on saved game A + code:88D7-FAAD+D4D7-FA6D + cheat + description:Start with about 1000 Energy Tanks on saved game A + code:35D7-FAAD+D7D7-FA6D + cheat + description:Start with about 1200 Energy Tanks on saved game A + code:CED7-FAAD+D0D7-FA6D + cheat + description:Start with about 1500 Energy Tanks on saved game A + code:28D7-FAAD+D9D7-FA6D + cheat + description:Invincibility (except for acid and when bosses grab you) (alt) + code:7E18A8:4C + cheat + description:Infinite energy (can combine with invincibility code) + code:7E09C2:63 + cheat + description:Kill most enemies on contact + code:7E0A6E:0F + cheat + description:Infinite Missiles (alt) + code:7E09C6:E7 + cheat + description:Infinite Missiles (alt 2) + code:7E09C6:E7+7E09C7:03 + cheat + description:Maximum 999 Missiles + code:7E09C8:E7+7E09C9:03 + cheat + description:Infinite Super Missiles (alt) + code:7E09CA:50 + cheat + description:Infinite Power Bombs (alt) + code:7E09CE:50 + cheat + description:Have all Guns except Charge Beam + code:7E09A8:FF + cheat + description:Have Charge Beam + code:7E09A9:FF + cheat + description:Have all suits and misc items (except Bombs) + code:7E09A4:FF + cheat + description:Have all boots and regular Bombs + code:7E09A5:FF + cheat + description:Have Missiles and Power Bombs + code:7E09CE:50 + cheat + description:Infinite time to escape ship + code:7E0945:00+7E0946:00+7E0947:01 + cheat + description:Full movement in Maridia sand (alt) + code:84B518:80+90981D:00 + cheat + description:Moon-jump + code:7E0B2D:44+7E0B2E:01 + cheat + description:0 hours played (alt) + code:7E09E0:00 + cheat + description:Brinstar mapped (alt) + code:7ED909:FF + cheat + description:Crateria mapped (alt) + code:7ED908:FF + cheat + description:Maridia mapped (alt) + code:7ED90C:FF + cheat + description:Norfair mapped (alt) + code:EED9-936D + cheat + description:Tourian mapped (alt) + code:7ED90D:FF + cheat + description:Wrecked Ship mapped (alt) + code:7ED90B:FF + cheat + description:Start with Missiles + code:7E09C8:01 + cheat + description:Start with Super Missiles + code:7E09CC:01 + cheat + description:Start with Power Bombs + code:7E09D0:01 + +cartridge sha256:40b46bb29785fb431b325f22377faa8b099be4d77aecc1f03000b8a4cb589b63 + title:Super Ninja Boy (USA) + cheat + description:Protection from most hazards (makes some side-view enemies invincible) + code:822E-07B0 + cheat + description:Don't subtract money (must have enough to buy) + code:1DAF-D4D6 + cheat + description:All stats are 20 (attack, defense, energy, max HP, max NP) + code:CB2F-A70C+3C2F-A7AC+F02F-A76C + cheat + description:All stats for every level are 50 + code:CB2F-A70C+3C2F-A7AC+742F-A76C + cheat + description:All stats for every level are 100 + code:CB2F-A70C+3C2F-A7AC+102F-A76C + cheat + description:All stats for every level are 255 + code:CB2F-A70C+3C2F-A7AC+EE2F-A76C + cheat + description:1 experience point required for level 2 + code:DF24-A4AC + cheat + description:1 experience point required for level 3 + code:DF24-A76C + cheat + description:1 experience point required for level 4 + code:DF27-AD0C + cheat + description:1 experience point required for level 5 + code:DF27-AFDC + cheat + description:Don't subtract M's for ninja cyclone attack + code:DD61-D725 + cheat + description:Don't subtract M's for mighty balls attack + code:DDA5-0421 + cheat + description:Skulls subtract 2 M's + code:D437-6420 + cheat + description:Skulls don't subtract an M + code:DD37-6420 + cheat + description:M power-ups worth nothing (handicap) + code:DD30-6720 + cheat + description:M power-ups worth 2 + code:D430-6720 + cheat + description:M power-ups worth 3 + code:D730-6720 + cheat + description:M power-ups worth 4 + code:D030-6720 + cheat + description:M power-ups worth 5 + code:D930-6720 + cheat + description:M power-ups set to 15 + code:F930-6720 + cheat + description:Start with 250 cash + code:EC81-AF69 + cheat + description:Start with 40,960 cash + code:6981-A4D9 + +cartridge sha256:a8acbbd6f8afbf289a6b837da6cd8bd109a00cd38625c956ab8ff739732d9e4f + title:Super Nova (USA) + cheat + description:Invincibility + code:0A84-C4A7+7984-C7D7+8384-C707 + cheat + description:Infinite lives + code:A268-4716 + cheat + description:Hit anywhere + code:6DA9-1DA7+DD87-1D41+DDA5-4FD7 + cheat + description:Keep main weapon after dying + code:C26C-4446 + cheat + description:Start with strongest main weapon + code:62C4-1F46 + +cartridge sha256:24b687f95bb9737d223738f13c00aeaa7d697fa9e2fd50597b81d0cfa2160daa + title:Super Off Road (USA) + cheat + description:Infinite nitros + code:D4B7-07AF+22B0-0FDF + cheat + description:Infinite cash - P1 + code:2BCA-6707 + cheat + description:Infinite cash - P2 + code:2B84-DDDD + cheat + description:Start with $500,000 + code:D987-6D0F + cheat + description:Start with $900,000 + code:DB87-6D0F + +cartridge sha256:16f9c90d75bd23d0620be00ecf818fcb25c5935d4ee26b1fe17b926f8987aa65 + title:Super Off Road - The Baja (USA) + cheat + description:Infinite nitros + code:3CA0-CD6F + cheat + description:Indestructible engine + code:C283-34D7 + cheat + description:Indestructible shocks + code:C28A-3D67 + cheat + description:Indestructible tires + code:C28C-3DD7 + cheat + description:Vehicle can take only about 60% damage + code:1D81-37D7 + cheat + description:Vehicle can take only about 35% damage + code:7D81-37D7 + cheat + description:$9,000 for brakes + code:DBB6-1FDF + cheat + description:$2,000 for brakes + code:D4B6-1FDF + cheat + description:$9,000 for tires + code:DBB6-1F6F + cheat + description:$2,000 for tires + code:D4B6-1F6F + cheat + description:$2,000 for shocks + code:D4B6-14DF + cheat + description:$9,000 for shocks + code:DBB6-14DF + cheat + description:$2,000 for lights + code:D4B6-146F + cheat + description:$9,000 for lights + code:DBB6-146F + cheat + description:$2,000 for engine + code:D4B6-17DF + cheat + description:$4,000 for engine + code:D0B6-17DF + +cartridge sha256:5a4b0c89606f71182fa5552ac476cc3bbda5ddc7d44e33f9184114aaea38020d + title:Super Play Action Football (USA) + cheat + description:One timeout each team + code:DFB7-D4D7 + cheat + description:No timeouts - P1 + code:10B7-D407 + cheat + description:No timeouts - P2 + code:10B7-D4A7 + cheat + description:Infinite time to select play + code:4067-6FDD + cheat + description:Less time to select play + code:F367-6D0D + cheat + description:More time to select play + code:5D67-6D0D + +cartridge sha256:a3d803b8c6b0b6ac55085671040b840f993543915c7f802e14fb651beabe9b63 + title:Super Punch-Out!! (USA) + cheat + description:Infinite health against most punches + code:C2A4-DFD4 + cheat + description:Gain max health after connecting a hit - both players + code:D9AD-DDA4 + cheat + description:Infinite time + code:C9E3-64DD + cheat + description:Opponent has no health + code:BAEC-D46D + cheat + description:Most opponents stay down for the count + code:DFAB-AFDD + cheat + description:Opponent does almost nothing + code:6D61-DFD0 + cheat + description:Some special attacks don't damage as much + code:C2AB-DFDF + cheat + description:Super Punch anytime + code:DDA1-A767 + cheat + description:Max power after one hit + code:CB34-AD07+F834-AD67+3C34-ADA7 + cheat + description:Infinite rematches + code:C2B8-64A5 + cheat + description:No rematches + code:DDB7-0704 + cheat + description:Fix game genied world circuit + code:CB84-DDA7+DD84-DFD7 + cheat + description:Start with 5 rematches + code:D1B7-0704 + cheat + description:Start with 8 rematches + code:DBB7-0704 + cheat + description:Start with half health - both players + code:49BC-6F6F + cheat + description:Start with very little health - both players + code:DFBC-6F6F + cheat + description:Start on world circuit + code:DB8A-D4A1+D48A-D7D1+3C8A-D701 + cheat + description:Infinite health + code:7E088F:50+7E089F:50 + cheat + description:Infinite time (alt) + code:7E0B27:03 + cheat + description:Infinite health (alt) + code:7E088F:50+7E089F:50 + cheat + description:Opponent has no health (alt) + code:7E099F:01 + cheat + description:Always cause dizziness + code:7E0938:8F + cheat + description:All hits cause super dizziness + code:7E092B:B0 + cheat + description:Max power (Super and Rapid Punch) + code:7E0899:00+7E089A:00+7E089B:00+7E089C:1B + cheat + description:TKO after only one knockdown + code:7E099D:03 + +cartridge sha256:05c7f6461209020785fba33007e1830820aa44ada4b1a6f991d936bf2335b15b + title:Super R-Type (USA) + cheat + description:Start with Invincibility (blinking) + code:82C2-DF61 + cheat + description:Infinite lives + code:C2C7-6D0F + cheat + description:Infinite FORCE once obtained + code:C267-A4D9 + cheat + description:Always fire charged shots (hold B) + code:7287-0FD1+DD87-0D61 + cheat + description:Spiral motion gun takes less time to power up + code:6D80-6DD1+DD80-6D01 + cheat + description:Spiral motion gun takes much less time to power up + code:DD80-6DA1 + cheat + description:Spiral motion gun can't get over-charged + code:6D84-6F01 + cheat + description:All FORCE satellites have 1 unit of power (but can't exceed 1 unit) + code:DD68-6DDB+CB6C-67AB+7D68-6D6B + cheat + description:All FORCE satellites have 2 units of power (but can't exceed 2 units) + code:DF68-6DDB+CB6C-67AB+7D68-6D6B + cheat + description:All FORCE satellites have 3 units of power + code:D468-6DDB+CB6C-67AB+7D68-6D6B + cheat + description:Start with 1 life instead of 3 + code:DF66-0F00+CB66-0FD0+DD66-0F60 + cheat + description:Start with 2 lives + code:D466-0F00+CB66-0FD0+DD66-0F60 + cheat + description:Start with 4 lives + code:D066-0F00+CB66-0FD0+DD66-0F60 + cheat + description:Start with 5 lives + code:D966-0F00+CB66-0FD0+DD66-0F60 + cheat + description:Start with 7 lives + code:D566-0F00+CB66-0FD0+DD66-0F60 + cheat + description:Start with 9 lives + code:DB66-0F00+CB66-0FD0+DD66-0F60 + cheat + description:Continue with 1 life instead of 3 + code:DF6C-A709+CB6C-A7D9+DD6C-A769 + cheat + description:Continue with 2 lives + code:D46C-A709+CB6C-A7D9+DD6C-A769 + cheat + description:Continue with 4 lives + code:D06C-A709+CB6C-A7D9+DD6C-A769 + cheat + description:Continue with 5 lives + code:D96C-A709+CB6C-A7D9+DD6C-A769 + cheat + description:Continue with 7 lives + code:D56C-A709+CB6C-A7D9+DD6C-A769 + cheat + description:Continue with 9 lives + code:DB6C-A709+CB6C-A7D9+DD6C-A769 + cheat + description:Start with Invincibility (blinking) (alt) + code:7E15BD:00 + +cartridge sha256:7a8ffaf8bb549b400ec2f0bda9f3c0dbf5852c38618cdb21cd783c368383e2c7 + title:Super Scope 6 (USA) + cheat + description:Add 1 bullets at a time (Blastris A) + code:DFC6-05D4 + cheat + description:Add 3 bullets at a time (Blastris A) + code:D7C6-05D4 + cheat + description:Add 5 bullets at a time (Blastris A) + code:D9C6-05D4 + cheat + description:Add 7 bullets at a time (Blastris A) + code:D5C6-05D4 + cheat + description:Add 9 bullets at a time (Blastris A) + code:DBC6-05D4 + cheat + description:Infinite bullets (Blastris A) + code:C9C2-D16F + cheat + description:Clear 1 line instead of 5 to advance to next level (Blastris A) + code:DFC9-056F + cheat + description:Clear 2 lines to advance to next level (Blastris A) + code:D4C9-056F + cheat + description:Clear 3 lines to advance to next level (Blastris A) + code:D7C9-056F + cheat + description:Clear 4 lines to advance to next level (Blastris A) + code:D0C9-056F + cheat + description:Select low mode to start on level 5 (Blastris B, Type B) + code:D968-D100 + cheat + description:Select low mode to start on level 15 (Blastris B, Type B) + code:DE68-D100 + cheat + description:Select low mode to start on level 25 (Blastris B, Type B) + code:FB68-D100 + cheat + description:Select low mode to start on level 30 (Blastris B, Type B) + code:F368-D100 + cheat + description:Select low mode to start on level 35 (Blastris B, Type B) + code:4768-D100 + cheat + description:Select low mode to start on level 40 (Blastris B, Type B) + code:4668-D100 + cheat + description:Clear stage after 1 Molian is hit (Mole Patrol, Stage Mode) + code:BAA6-01DD + cheat + description:Take no damage (LazerBlazer, Type A) + code:8262-64A1 + cheat + description:Take no damage (LazerBlazer Game, Type B) + code:3CB0-670B + cheat + description:Take no damage (LazerBlazer Game, Type C) + code:C269-67DE + +cartridge sha256:72268d692f03f9c012844edac1febe0b77932268b3b37ad55d6ccf631cda8483 + title:Super Shadow of the Beast (USA) (Proto) + cheat + description:Invincibility + code:C26F-0FA4+626E-DDA4+2D6D-0D64 + cheat + description:Infinite health + code:A964-0D04 + cheat + description:Infinite lives + code:C964-0D04 + cheat + description:Infinite credits + code:A965-046D + cheat + description:Moon-jump + code:C2B0-6D67+C26B-6FA7 + +cartridge sha256:8b75ab4bb1b63c45a56e7a4c5a37c0864f14375ab3131edc33489764426ad888 + title:Super Smash T.V. (USA) + cheat + description:Invincibility on mobile force field pick-up + code:6D65-6403+DF65-6463 + cheat + description:Weapons gauge doesn't lose power until you die (don't combine with don't lose weapon power code) + code:8283-67D7 + cheat + description:Don't lose weapon power after death (don't combine with weapons gauge doesn't lose power code) + code:6DB8-D404+DFB8-D464 + cheat + description:Infinite credits (if continue timer runs out and player starts, a credit gets used) + code:C223-D78B + cheat + description:Infinite lives + code:82BB-DD04 + cheat + description:Bonus life worth nothing + code:8284-AF03 + cheat + description:Join in with 2 lives - P1 + code:EEBF-D7A4 + cheat + description:Join in with 3 lives - P1 + code:DDBF-D7A4 + cheat + description:Join in with 4 lives - P1 + code:DFBF-D7A4 + cheat + description:Join in with 5 lives - P1 + code:D4BF-D7A4 + cheat + description:Join in with 7 lives - P1 + code:D0BF-D7A4 + cheat + description:Join in with 8 lives - P1 + code:D9BF-D7A4 + cheat + description:Join in with 9 lives - P1 + code:D1BF-D7A4 + cheat + description:2 lives after continue - P1 + code:EEB1-D7A4 + cheat + description:3 lives after continue - P1 + code:DDB1-D7A4 + cheat + description:4 lives after continue - P1 + code:DFB1-D7A4 + cheat + description:5 lives after continue - P1 + code:D4B1-D7A4 + cheat + description:7 lives after continue - P1 + code:D0B1-D7A4 + cheat + description:8 lives after continue - P1 + code:D9B1-D7A4 + cheat + description:9 lives after continue - P1 + code:D1B1-D7A4 + cheat + description:10 lives after continue - P1 + code:D5B1-D7A4 + cheat + description:2 lives after continue - P2 + code:EEB0-DDA4 + cheat + description:3 lives after continue - P2 + code:DDB0-DDA4 + cheat + description:4 lives after continue - P2 + code:DFB0-DDA4 + cheat + description:5 lives after continue - P2 + code:D4B0-DDA4 + cheat + description:7 lives after continue - P2 + code:D0B0-DDA4 + cheat + description:8 lives after continue - P2 + code:D9B0-DDA4 + cheat + description:9 lives after continue - P2 + code:D1B0-DDA4 + cheat + description:10 lives after continue - P2 + code:D5B0-DDA4 + cheat + description:Start with 0 continues + code:DD62-0F0D + cheat + description:Start with 1 continue + code:DF62-0F0D + cheat + description:Start with 2 continues + code:D462-0F0D + cheat + description:Start with 3 continues + code:D762-0F0D + cheat + description:Start with 5 continues + code:D962-0F0D + cheat + description:Start with 6 continues + code:D162-0F0D + cheat + description:Start with 7 continues + code:D562-0F0D + cheat + description:Start with 8 continues + code:D662-0F0D + cheat + description:Start with 9 continues + code:DB62-0F0D + cheat + description:Start with 3 lives + code:DD62-076D + cheat + description:Start with 4 lives + code:DF62-076D + cheat + description:Start with 5 lives + code:D462-076D + cheat + description:Start with 7 lives + code:D062-076D + cheat + description:Start with 8 lives + code:D962-076D + cheat + description:Start with 9 lives + code:D162-076D + cheat + description:Start with 10 lives + code:D562-076D + cheat + description:Invincibility - P1 + code:7E18A5:00 + cheat + description:Invincibility - P2 + code:7E18A6:00 + cheat + description:Infinite Shield - P1 + code:7E18A9:01 + cheat + description:Infinite Shield - P2 + code:7E18AA:01 + cheat + description:Infinite lives - P1 + code:7E0531:09 + cheat + description:Infinite lives - P2 + code:7E0532:09 + cheat + description:Max weapon gauge - P1 + code:7E1899:06 + cheat + description:Max weapon gauge - P2 + code:7E189A:06 + cheat + description:Have Rapid Fire - P1 + code:7E18B0:04 + cheat + description:Have Rapid Fire - P2 + code:7E18B1:04 + cheat + description:Have normal weapon - P1 + code:7E1897:00 + cheat + description:Have normal weapon - P2 + code:7E1898:00 + cheat + description:Have Spread weapon - P1 + code:7E1897:01 + cheat + description:Have Spread weapon - P2 + code:7E1898:01 + cheat + description:Have Rockets - P1 + code:7E1897:02 + cheat + description:Have Rockets - P2 + code:7E1898:02 + cheat + description:Have Grenade Launcher - P1 + code:7E1897:03 + cheat + description:Have Grenade Launcher - P2 + code:7E1898:03 + cheat + description:Have Grenade Lobber (glitchy) - P1 + code:7E1897:04 + cheat + description:Have Grenade Lobber (glitchy) - P2 + code:7E1898:04 + cheat + description:Have Speed Shoes - P1 + code:7E18AD:FF + cheat + description:Have Speed Shoes - P2 + code:7E18AE:FA + cheat + description:Have 10 Keys + code:7E05B1:0A + cheat + description:Turbo mode on + code:7E052E:01 + cheat + description:Circuit warp on + code:7E020E:01 + cheat + description:Infinite credits (alt) + code:7E0533:09 + +cartridge sha256:694ad2b34ab808bd8a1aa9dda359594cfd3a5fd9d95d4cf262ccaa0eb57eef67 + title:Super Soccer (USA) + cheat + description:Each goal worth 2 - P1 + code:FC2A-0F65+3C2A-0FA5 + cheat + description:Each goal worth 3 - P1 + code:FC2A-0F65+FC2A-0FA5 + cheat + description:Each goal worth 4 - P1 + code:1B2A-0F65+D72A-0FA5 + cheat + description:Each goal worth 5 - P1 + code:1B2A-0F65+D02A-0FA5 + cheat + description:Each goal worth 6 - P1 + code:1B2A-0F65+D92A-0FA5 + cheat + description:Each goal worth 7 - P1 + code:1B2A-0F65+D12A-0FA5 + cheat + description:Each goal worth 8 - P1 + code:1B2A-0F65+D52A-0FA5 + cheat + description:Each goal worth 9 - P1 + code:1B2A-0F65+D62A-0FA5 + cheat + description:Each goal worth 2 - P2 + code:FC22-0465+3C22-04A5 + cheat + description:Each goal worth 3 - P2 + code:FC22-0465+FC22-04A5 + cheat + description:Each goal worth 4 - P2 + code:1B22-0465+D722-04A5 + cheat + description:Each goal worth 5 - P2 + code:1B22-0465+D022-04A5 + cheat + description:Each goal worth 6 - P2 + code:1B22-0465+D922-04A5 + cheat + description:Each goal worth 7 - P2 + code:1B22-0465+D122-04A5 + cheat + description:Each goal worth 8 - P2 + code:1B22-0465+D522-04A5 + cheat + description:Each goal worth 9 - P2 + code:1B22-0465+D622-04A5 + cheat + description:Timer continues to count when it is normally stopped (pause can still stop time) + code:DDA6-0DD1 + +cartridge sha256:5eb9736d66b3ac730ebbfdd19ef2397282b5f1a62dc0048093e041e23b807741 + title:Super Soccer Champ (USA) + cheat + description:Faster timer + code:F32B-D400 + cheat + description:Slower timer + code:5D2B-D400 + cheat + description:Faster Brazil strikers + code:D4E7-6DEF + cheat + description:Faster USA strikers + code:D4E0-6DEF + cheat + description:Faster England strikers + code:D4ED-6DEF + cheat + description:Faster Germany strikers + code:D4E3-0DEF + cheat + description:Faster Italy strikers + code:D4EF-6DEF + cheat + description:Faster Holland strikers + code:D4E4-6DEF + cheat + description:Faster Argentina strikers + code:D4EE-0DEF + cheat + description:Faster France strikers + code:D4E9-6DEF + +cartridge sha256:298b643fec4208f33d02a7afbb05c6f757b0086be533f8ca739466cbe96ae918 + title:Super Star Wars (USA) (Rev 1) + cheat + description:Protection against most damage + code:1D34-C704 + cheat + description:Infinite lives + code:C232-14D4+CB6C-3767 + cheat + description:Infinite continues + code:4A21-14D5 + cheat + description:Blaster power-ups remain after dying + code:553A-1764 + cheat + description:Hit anywhere - Side-scrolling levels + code:1D89-1407+2D89-14D7+AD89-1F07+DD81-1DA7+DD89-1F67+DD89-1FA7 + cheat + description:Only 1 Jawa needed to pass landspeeder levels + code:DF67-4FAF+DF60-4D6F + cheat + description:Only 5 Jawas needed to pass landspeeder levels + code:D967-4FAF+D960-4D6F + cheat + description:Only 10 Jawas needed to pass landspeeder levels + code:DC67-4FAF+DC60-4D6F + cheat + description:25 Jawas needed to pass landspeeder levels + code:FB67-4FAF+FB60-4D6F + cheat + description:50 Jawas needed to pass landspeeder levels + code:7467-4FAF+7460-4D6F + cheat + description:No fuel maximum for fuel power-ups + code:6DA5-4D04 + cheat + description:Fuel power-ups completely refill the landspeeder + code:40A1-47D4 + cheat + description:Small hearts restore 1/2 health (easy level) + code:D43B-CF00 + cheat + description:Small hearts restore 1/2 health (brave level) + code:DF3B-CFA0 + cheat + description:Small hearts restore 1/2 health (Jedi level) + code:DF3B-C400 + cheat + description:Small hearts restore 2x health (easy level) + code:D13B-CF00 + cheat + description:Small hearts restore 2x health (brave level) + code:D03B-CFA0 + cheat + description:Small hearts restore 2x health (Jedi level) + code:D03B-C400 + cheat + description:Small hearts restore 4x health (easy level) + code:DA3B-CF00 + cheat + description:Small hearts restore 4x health (brave level) + code:D63B-CFA0 + cheat + description:Small hearts restore 4x health (Jedi level) + code:D63B-C400 + cheat + description:Han Solo and Chewbacca start with a blaster + code:DD88-37A5 + cheat + description:Han Solo and Chewbacca start with a seeker gun + code:D488-37A5 + cheat + description:Han Solo and Chewbacca start with a rapid ion gun + code:D788-37A5 + cheat + description:Han Solo and Chewbacca start with a plasma gun + code:D088-37A5 + cheat + description:Have character select menu on a new game + code:DDB9-CF67 + cheat + description:Have Lightsaber on a new game + code:DDB0-C767 + cheat + description:Start with 1/2 fuel on landspeeder levels + code:F467-4D0F + cheat + description:Start with 2x fuel on landspeeder levels + code:0667-4D0F + cheat + description:Start with 2 lives + code:DF35-CDA0 + cheat + description:Start with 6 lives + code:D935-CDA0 + cheat + description:Start with 8 lives + code:D535-CDA0 + cheat + description:Start with 11 lives + code:DC35-CDA0 + cheat + description:Start with 16 lives + code:DE35-CDA0 + cheat + description:Start with 26 lives + code:FB35-CDA0 + cheat + description:Start with 51 lives + code:7435-CDA0 + cheat + description:Start with 100 lives + code:1735-CDA0 + cheat + description:Start with no continues + code:DD3B-C760 + cheat + description:Start with 5 continues + code:D93B-C760 + cheat + description:Start with 7 continues + code:D53B-C760 + cheat + description:Start with 10 continues + code:DC3B-C760 + cheat + description:Start with 15 continues + code:DE3B-C760 + cheat + description:Start with 25 continues + code:FB3B-C760 + cheat + description:Start with 50 continues + code:743B-C760 + cheat + description:Start with 99 continues + code:173B-C760 + cheat + description:Start with 1/2 health (easy level) + code:F435-CFA0 + cheat + description:Start with 1/2 health (brave level) + code:FD35-C400 + cheat + description:Start with 1/2 health (Jedi level) + code:D335-C4A0 + cheat + description:Start with 2x health (easy level) + code:0635-CFA0 + cheat + description:Start with 2x health (brave level) + code:0D35-C400 + cheat + description:Start with 2x health (Jedi level) + code:7635-C4A0 + cheat + description:Infinite health + code:7E0A79:FF + cheat + description:Infinite time + code:7E096F:0F + cheat + description:Infinite Shields + code:7E0988:01 + cheat + description:Infinite lives + code:7E08FB:03 + cheat + description:Infinite Thermal Detonators + code:7E0978:06 + cheat + description:Infinite Fighter Life + code:7E0876:64 + cheat + description:Infinite Torpedoes + code:7E0878:63 + cheat + description:Always have Plasma Gun + code:7E0985:04 + cheat + description:Always have Rapid Ion + code:7E0985:03 + cheat + description:Always have Seeker Gun + code:7E0985:02 + cheat + description:Have Lightsaber and character select menu on a new game + code:7E0110:C0 + +cartridge sha256:c6bd7239cb2074ff1c471d14535bead6290bba2d7c75b4f03209cb114877b4c8 + title:Super Star Wars (USA) + cheat + description:Hit anywhere - Side-scrolling levels + code:1D8B-1467+2D8B-1407+AD8B-1F67+DD8B-14D7+DD8B-1FA7+DD8C-1FD7 + cheat + description:Infinite health + code:7E0A79:FF + cheat + description:Infinite time + code:7E096F:0F + cheat + description:Infinite Shields + code:7E0988:01 + cheat + description:Infinite lives + code:7E08FB:03 + cheat + description:Infinite Thermal Detonators + code:7E0978:06 + cheat + description:Infinite Fighter Life + code:7E0876:64 + cheat + description:Infinite Torpedoes + code:7E0878:63 + cheat + description:Always have Plasma Gun + code:7E0985:04 + cheat + description:Always have Rapid Ion + code:7E0985:03 + cheat + description:Always have Seeker Gun + code:7E0985:02 + cheat + description:Have Lightsaber and character select menu on a new game + code:7E0110:C0 + +cartridge sha256:f7df5cd16ce6624567d1a24e9b9c0b9050ea9b6a9fe5a7973484589637756596 + title:Super Star Wars - Return of the Jedi (USA) (Rev 1) + cheat + description:Infinite lives + code:C230-CF0F + cheat + description:Infinite Force power when you use the Force Saber + code:C234-34AA + cheat + description:Always have shield + code:CB6E-4704 + cheat + description:Once you have thermal detonator you keep it (disable to use force power) + code:C222-3769 + cheat + description:Infinite Force power when you use the Freeze Force + code:C281-3DB9 + cheat + description:Finish the first level almost instantly + code:1BBD-C703+EEBD-C763+EEBD-C7A3 + cheat + description:Start with 1 life + code:DD82-C7B1 + cheat + description:Start with 5 lives + code:D082-C7B1 + cheat + description:Start with 10 lives + code:DB82-C7B1 + cheat + description:Start with 25 lives + code:F682-C7B1 + cheat + description:Start with very little health + code:CB8E-3D21+DF8E-3FF1+DD8E-3F91 + cheat + description:Start with about 1/4 health + code:CB8E-3D21+DE8E-3FF1+DD8E-3F91 + cheat + description:Start with about 1/2 health + code:CB8E-3D21+FD8E-3FF1+DD8E-3F91 + cheat + description:Start with about 3/4 health + code:CB8E-3D21+FE8E-3FF1+DD8E-3F91 + +cartridge sha256:46370b3bd6ff9ee04c425eef0f482f521f3b61bd4b058f2f4e9d322253d7b5de + title:Super Star Wars - The Empire Strikes Back (USA) (Rev 1) + cheat + description:Almost invincible - except spikes (works for enemy too) + code:483F-376F + cheat + description:Infinite lives + code:C238-C70F + cheat + description:Infinite continues + code:C229-4DD1 + cheat + description:Infinite thermal detonators + code:6DE9-47AF + cheat + description:Elevation and Freeze don't drain force bar + code:C229-14F9 + cheat + description:Saber control doesn't drain force bar + code:DDCC-1DDA + cheat + description:Mind control, Slow, Deflect and Invisible don't drain force bar + code:C22F-C7F9 + cheat + description:Keep gun power-ups after dying + code:C238-CD6F + cheat + description:Shield power-ups don't last as long + code:DD81-3DD4 + cheat + description:Shield power-ups last longer + code:D481-3DD4 + cheat + description:Shield power-ups last much longer + code:D781-3DD4 + cheat + description:Shield power-ups last a very long time + code:DE81-3DD4 + cheat + description:Health sword power-ups add 1/2 as much + code:D484-37A4 + cheat + description:Health sword power-ups add 2x as much + code:D684-37A4 + cheat + description:Health sword power-ups add 4x as much + code:FD84-37A4 + cheat + description:Force orbs add 1/2 as much + code:F68B-3764 + cheat + description:Force orbs add 2x as much + code:1D8B-3764 + cheat + description:Force orbs fill force bar + code:EE8B-3764 + cheat + description:Small hearts heal less on Easy + code:DF2B-C465 + cheat + description:Small hearts heal 2x as much on Easy + code:D12B-C465 + cheat + description:Small hearts heal 4x as much on Easy + code:DA2B-C465 + cheat + description:Small hearts heal very much on Easy + code:4D2B-C465 + cheat + description:Small hearts heal completely on Easy + code:002B-C465 + cheat + description:Small hearts heal less on Brave level + code:DF2B-C7D5 + cheat + description:Small hearts heal 2x as much on Brave + code:D02B-C7D5 + cheat + description:Small hearts heal 4x as much on Brave + code:D62B-C7D5 + cheat + description:Small hearts heal very much on Brave + code:4D2B-C7D5 + cheat + description:Small hearts heal completely on Brave + code:002B-C7D5 + cheat + description:Small hearts heal less on Jedi level + code:DF2B-C765 + cheat + description:Small hearts heal 2x as much on Jedi + code:D02B-C765 + cheat + description:Small hearts heal 4x as much on Jedi + code:D62B-C765 + cheat + description:Small hearts heal very much on Jedi + code:4D2B-C765 + cheat + description:Small hearts heal completely on Jedi + code:002B-C765 + cheat + description:Big hearts heal 1/2 your health instead of 1/4 + code:3C8D-3D04 + cheat + description:Big hearts heal completely + code:DC8D-3D04 + cheat + description:Continue with 2 lives on Easy + code:DF21-C465 + cheat + description:Continue with 6 lives on Easy + code:D921-C465 + cheat + description:Continue with 21 lives on Easy + code:F021-C465 + cheat + description:Continue with 51 lives on Easy + code:7421-C465 + cheat + description:Continue with 2 lives on Jedi + code:DF21-C765 + cheat + description:Continue with 6 lives on Jedi + code:D921-C765 + cheat + description:Continue with 21 lives on Jedi + code:F021-C765 + cheat + description:Continue with 100 lives on Jedi + code:1721-C765 + cheat + description:Tauntaun starts with 1/2 usual health + code:4D20-CF2F + cheat + description:Tauntaun starts with 3/4 usual health + code:7D20-CF2F + cheat + description:Tauntaun starts with a little more health than usual + code:0020-CF2F + cheat + description:Start with all force abilities + code:6D23-47F9 + cheat + description:Start with Flame gun - 1st life only + code:622C-47D0 + cheat + description:Start with 2 lives on Brave + code:DF21-C7D5 + cheat + description:Start with 6 lives on Brave + code:D921-C7D5 + cheat + description:Start with 21 lives on Brave + code:F021-C7D5 + cheat + description:Start with 100 lives on Brave + code:1721-C7D5 + cheat + description:Start with 1 continue + code:DF2C-CDA5 + cheat + description:Start with 5 continues + code:D92C-CDA5 + cheat + description:Start with 9 continues + code:DB2C-CDA5 + cheat + description:Start with 1/2 as much health on Easy + code:F425-CDD5 + cheat + description:Start with 3/4 as much health on Easy + code:F625-CDD5 + cheat + description:Start with more health on Easy + code:4C25-CDD5 + cheat + description:Start with much more health on Easy + code:7D25-CDD5 + cheat + description:Start with maximum health on Easy + code:0025-CDD5 + cheat + description:Start with 1/2 as much health on Brave + code:FD25-CD65 + cheat + description:Start with 3/4 as much health on Brave + code:F625-CD65 + cheat + description:Start with more health on Brave + code:4C25-CD65 + cheat + description:Start with much more health on Brave + code:7D25-CD65 + cheat + description:Start with maximum health on Brave + code:0025-CD65 + cheat + description:Start with half as much health on Jedi + code:D325-CFD5 + cheat + description:Start with 3/4 as much health on Jedi + code:F925-CFD5 + cheat + description:Start with no continues + code:DD2C-CDA5 + cheat + description:Start on level 1-2 + code:D469-1707 + cheat + description:Start on level 1-3 + code:D169-1707 + cheat + description:Start on level 1-4 + code:D769-1707 + cheat + description:Start on level 1-5 + code:D969-1707 + cheat + description:Start on level 1-6 + code:D069-1707 + cheat + description:Start on level 1-7 + code:DB69-1707 + cheat + description:Start on level 1-8 + code:F969-1707 + cheat + description:Start on level 1-10 + code:D569-1707 + cheat + description:Start on Hoth 3D level + code:D369-17D7+DC69-1707 + cheat + description:Start on level 1-11 + code:D669-1707 + cheat + description:Start on Asteroids level + code:F469-17D7+DD69-1707 + cheat + description:Start on level 3-1 + code:DA69-1707 + cheat + description:Start on level 3-2 + code:D269-1707 + cheat + description:Start on level 3-3 + code:D369-1707 + cheat + description:Start on Cloud City 3D level + code:D369-17D7+FC69-1707 + cheat + description:Start on level 4-2 + code:DE69-1707 + cheat + description:Start on level 4-3 + code:F769-1707 + cheat + description:Start on level 4-4 + code:F469-1707 + cheat + description:Start on level 4-5 + code:FD69-1707 + cheat + description:Start on level 4-6 + code:F569-1707 + cheat + description:Start on level 4-7 + code:F669-1707 + cheat + description:Start on Darth Vader level + code:F169-1707 + +cartridge sha256:d17cb5c73174060fcbd9cba6c705643f19c3b8be24d0f7ee43aee674ff1ea38e + title:Super Street Fighter II (USA) + cheat + description:Invincibility (except against throws, projectiles don't work) - P1 + code:6D9C-8D67+DF9C-8DA7+6DA1-8FD5+D4A1-8F05+6DAF-7405+D4AF-7465 + cheat + description:Infinite health - P1 + code:CB96-7DDD+8D96-7D0D+6296-7D6D+7F96-7DAD+D996-7FDD + cheat + description:Don't take damage except from throws or grabs - both players + code:3C10-7467+3C10-74A7 + cheat + description:Hit anywhere (except projectiles) - P1 + code:3D1D-5DDF+8D1D-5DAF+0D1D-5D0F+D51D-5D6F + cheat + description:1st normal hit wins - except throws or grabs + code:DD10-7707 + cheat + description:No charging required for some special moves + code:D002-EDD5 + cheat + description:Some special moves can be done in the air + code:DD47-8DD1 + cheat + description:Dizziness doesn't last + code:1077-7F61 + cheat + description:Every hit sets opponent on fire + code:CB17-8FAD+7D17-84DD + cheat + description:Every hit sets the opponent on fire and knocks him down + code:CB17-8FAD+F617-84DD + cheat + description:Every hit zaps the opponent and knocks him down + code:CB17-8FAD+FC17-84DD + cheat + description:Every hit knocks the opponent down + code:CB17-8FAD+FA17-84DD + cheat + description:Every hit is a "hard hit" - opponent almost never gets knocked down + code:CB17-8FAD+DC17-84DD + cheat + description:Players jump slower (not functional for CPU) + code:CB79-EF61+D579-EFA1 + cheat + description:Players jump faster (not functional for CPU) + code:CB79-EF61+D879-EFA1 + cheat + description:Each battle lasts only 1 round + code:DF81-E404 + cheat + description:Speed up timer + code:FE0C-7FDD + cheat + description:Slow down timer + code:9C0C-7FDD + cheat + description:P2 starts right in front of P1 + code:F122-E760 + cheat + description:Start with 1/4 health - both players + code:4A9C-7FDF + cheat + description:Start with 1/2 health - both players + code:969C-7FDF + cheat + description:Start with 3/4 health - both players + code:609C-7FDF + cheat + description:Balrog - Fierce charging punch, does heavy damage + code:6E6A-EF90 + cheat + description:Balrog - Roundhouse charging uppercut, does heavy damage + code:6E62-E790 + cheat + description:Balrog - Fierce shoulder butt, does heavy damage + code:6E69-5799 + cheat + description:Balrog - Faster turn punch - roundhouse + code:D18C-74D5 + cheat + description:Balrog - Superfast turn punch - roundhouse + code:DB8C-74D5 + cheat + description:Blanka - Fierce forward ball, does heavy damage + code:6E1C-E720 + cheat + description:Blanka - Beast leap, does heavy damage + code:6E1B-7D29 + cheat + description:Blanka - Jab zap, does heavy damage + code:6E15-ED20 + cheat + description:Cammy - Fierce spin knuckle, does heavy damage + code:6EB3-5F20 + cheat + description:Cammy - Roundhouse front kick, does heavy damage + code:6EBB-5720 + cheat + description:Cammy - Roundhouse cannon drill, from far away, does heavy damage + code:6EBF-5420 + cheat + description:Cammy - Erratic cannon drill + code:D1BE-E7A0 + cheat + description:Cammy - Superfast cannon drill + code:DDBE-E760 + cheat + description:Cammy - Superfast front kick - fierce + code:D620-17FA + cheat + description:Cammy - Superfast front kick - strong + code:D620-149A + cheat + description:Cammy - Superfast front kick - jab + code:D620-14FA + cheat + description:Chun-Li - Fierce fireball, does heavy damage + code:6E5D-7D20 + cheat + description:Chun-Li - Down step, does heavy damage + code:DE10-5425 + cheat + description:Chun-Li - Short lightning kick, does heavy damage + code:6E11-8425 + cheat + description:Chun Li - Faster whirlwind kick - roundhouse + code:D15E-8F60 + cheat + description:Chun Li - Superfast whirlwind kick - roundhouse + code:DB5E-8F60 + cheat + description:Dee Jay - Fierce hyper fist (1st hit), does heavy damage + code:6EC5-EF99 + cheat + description:Dee Jay - Fierce Max Out, does heavy damage + code:6ECF-7D91 + cheat + description:Dee Jay - Roundhouse dread kick, does heavy damage + code:6EC3-8F99 + cheat + description:Dee Jay - Dread kick is faster - fierce + code:DB23-179A + cheat + description:Dee Jay - Dread kick is faster - strong + code:DB23-1F9A + cheat + description:Dhalsim - Yoga spear, does heavy damage + code:DE5E-8729 + cheat + description:Dhalsim - Strong yoga flame (solid hit), does heavy damage + code:6E5E-E429 + cheat + description:Dhalsim - Fierce yoga fire, does heavy damage + code:6E58-E729 + cheat + description:E Honda - Jab hundred-hand slap, does heavy damage + code:6E99-8795 + cheat + description:E Honda - Fierce torpedo, does heavy damage + code:6E96-E495 + cheat + description:E Honda - Fierce sumo splash, does heavy damage + code:6E92-E795 + cheat + description:Fei Long - Fierce slide punch (1st hit), does heavy damage + code:6EC7-5F20 + cheat + description:Fei Long - Fierce slide punch (2nd hit), does heavy damage + code:6EC0-5D20 + cheat + description:Fei Long - Fierce slide punch (3rd hit), does heavy damage + code:6EC0-5720 + cheat + description:Fei Long - Roundhouse dragon kick, does heavy damage + code:6ECE-7420 + cheat + description:Fei Long - Superfast rekka-ken - strong + code:D528-1D2A + cheat + description:Fei Long - Superfast rekka-ken - fierce + code:D627-1F2A + cheat + description:Guile - Fierce sonic boom, does heavy damage + code:6E16-5491 + cheat + description:Guile - Roundhouse sonic kick, extremely close range, does heavy damage + code:6E1E-7491 + cheat + description:Hawk - The Hawk, does heavy damage + code:6EB3-5F91 + cheat + description:Ken - Fierce dragon punch, close to opponent, does heavy damage + code:6E96-8721 + cheat + description:Ken - Fierce fireballs, close to opponent, does heavy damage + code:6E92-8F21 + cheat + description:Ken - Roundhouse hurricane kick while on the ground, does heavy damage + code:6E9A-5721 + cheat + description:Ken - No delay after throwing fireball + code:3169-57A5 + cheat + description:Ken - Hurricane kicks rise higher when done in mid-air + code:1060-E405 + cheat + description:Ken - Faster hurricane kicks - roundhouse + code:D1A9-1DBA + cheat + description:Ken - Super fast hurricane kicks - roundhouse + code:DBA9-1DBA + cheat + description:M. Bison - Super fast psycho crusher - fierce + code:DB2F-CD9A + cheat + description:M. Bison - Psycho crusher in one place - fierce + code:1086-5D00 + cheat + description:Ryu - Jab dragon punch, close to opponent, does heavy damage + code:6E9D-8729 + cheat + description:Ryu - Fierce red fireballs from far away, does heavy damage + code:6E9B-E429 + cheat + description:Ryu - Roundhouse hurricane kick in the air, does heavy damage + code:6E9D-E429 + cheat + description:Ryu - No delay after throwing fireball + code:3169-57A5 + cheat + description:Ryu - Hurricane kicks rise higher when done in mid-air + code:1060-E405 + cheat + description:Ryu - Faster hurricane kicks - roundhouse + code:D1A9-1DBA + cheat + description:Ryu - Super fast hurricane kicks - roundhouse + code:DBA9-1DBA + cheat + description:Sagat - Roundhouse low tiger, from far away, does heavy damage + code:6E64-5F20 + cheat + description:Sagat - Fierce high tiger, from far away, does heavy damage + code:6E62-7720 + cheat + description:Sagat - Short tiger knee, does heavy damage + code:6E53-ED25 + cheat + description:Sagat - Jab projectiles move slower for everyone but Sagat, does heavy damage + code:EE27-479E + cheat + description:Sagat - Jab projectiles move slower for Sagat, does heavy damage + code:EE20-4D2E + cheat + description:Sagat - Fierce projectiles move faster for everyone but Sagat, does heavy damage + code:EC20-4D9E + cheat + description:Sagat - Fierce projectiles move faster for Sagat, does heavy damage + code:E520-4F2E + cheat + description:Vega - Fierce claw dive, does heavy damage + code:AE6A-8491 + cheat + description:Vega - Rolling claw attack, does heavy damage + code:6E62-8F91 + cheat + description:Vega - Claw thrust, does heavy damage + code:6E6E-EF91 + cheat + description:Vega - Superfast claw roll + code:D553-5F00 + cheat + description:Vega - Claw roll in one place + code:1053-5760 + cheat + description:Zangief - Double spinning lariat (only certain hits), does heavy damage + code:6E51-EF90 + cheat + description:Zangief - Spinning clothesline, does heavy damage + code:6E5F-ED90 + cheat + description:Infinite health - P1 (alt) + code:7E0531:B0 + cheat + description:Instant win - P1 + code:7E0771:FF + cheat + description:Infinite time + code:7E1929:99 + +cartridge sha256:830c900083cccc6ded74c167c4e257db34df4786ecd6e2f053de454db7d31fe5 + title:Super Strike Eagle (USA) + cheat + description:Infinite fuel + code:C9BD-47A4 + cheat + description:Infinite ammo - air-to-air mode + code:DD2A-3D64 + cheat + description:Infinite Maverick Missiles + code:82CD-3FD7 + cheat + description:Infinite Sidewinder Missiles + code:C92F-44A7 + cheat + description:Infinite Chaff + code:3C2A-4707 + cheat + description:Infinite Flares + code:3C26-4FD7 + cheat + description:Use up ammo faster - air-to-air mode + code:DC2A-3D64 + cheat + description:Start with 0 Chaff instead of 12 + code:DD3F-0F61 + cheat + description:Start with 6 Chaff + code:D13F-0F61 + cheat + description:Start with 50 Chaff + code:743F-0F61 + cheat + description:Start with 99 Chaff + code:173F-0F61 + cheat + description:Start with 0 Flares instead of 12 + code:DD3F-04A1 + cheat + description:Start with 6 Flares + code:D13F-04A1 + cheat + description:Start with 50 Flares + code:743F-04A1 + cheat + description:Start with 99 Flares + code:173F-04A1 + cheat + description:Start with 2 Sidewinder missiles instead of 12 + code:D437-0401 + cheat + description:Start with 25 Sidewinder Missiles + code:FB37-0401 + cheat + description:Start with 50 Sidewinder Missiles + code:7437-0401 + cheat + description:Start with 99 Sidewinder Missiles + code:1737-0401 + cheat + description:Start with less fuel + code:0D3D-0701 + +cartridge sha256:6e45a80ea148654514cb4e8604a0ffcbc726946e70f9e0b9860e36c0f3fa4877 + title:Super Tennis (USA) + cheat + description:Super speed - Matt + code:D060-AFAF+D761-AFAF+DD24-07A5 + cheat + description:Super speed - Amy + code:D060-AFAF+D761-AFAF+DD24-A7A5 + cheat + description:Super speed - Brian + code:D060-AFAF+D761-AFAF+DD27-07A5 + cheat + description:Super speed - Ki + code:D060-AFAF+D761-AFAF+DD27-A7A5 + cheat + description:Super speed - Phil + code:D060-AFAF+D761-AFAF+DD20-07A5 + cheat + description:Super speed - Lisa + code:D060-AFAF+D761-AFAF+DD20-A7A5 + cheat + description:Super speed - John + code:D060-AFAF+D761-AFAF+DD29-07A5 + cheat + description:Super speed - Erin + code:D060-AFAF+D761-AFAF+DD29-A7A5 + cheat + description:Super speed - Meyer + code:D060-AFAF+D761-AFAF+DD21-07A5 + cheat + description:Super speed - Donna + code:D060-AFAF+D761-AFAF+DD21-A7A5 + cheat + description:Super speed - Rich + code:D060-AFAF+D761-AFAF+DD25-07A5 + cheat + description:Super speed - Debbie + code:D060-AFAF+D761-AFAF+DD25-A7A5 + cheat + description:Super speed - Hiro + code:D060-AFAF+D761-AFAF+DD26-07A5 + cheat + description:Super speed - Colette + code:D060-AFAF+D761-AFAF+DD26-A7A5 + cheat + description:Super speed - Steve + code:D060-AFAF+D761-AFAF+DD2B-07A5 + cheat + description:Super speed - Nancy + code:D060-AFAF+D761-AFAF+DD2B-A7A5 + cheat + description:Super speed - Rob + code:D060-AFAF+D761-AFAF+DD2C-07A5 + cheat + description:Super speed - Yuka + code:D060-AFAF+D761-AFAF+DD2C-A7A5 + cheat + description:Super speed - Mar + code:D060-AFAF+D761-AFAF+DD28-07A5 + cheat + description:Super speed - Barb + code:D060-AFAF+D761-AFAF+DD28-A7A5 + +cartridge sha256:02cb7f1ed21ed6bfb9eaa0e91df2adb063a9bf4cbd6feb6cd024d676829e227e + title:Super Troll Islands (USA) + cheat + description:Infinite health (except spikes) + code:7E215A:04 + cheat + description:Max score + code:7E2009:99+7E200A:99+7E200B:99+7E200C:09 + cheat + description:Infinite whirlwinds + code:7E2074:09 + cheat + description:Infinite cupcakes + code:7E20F7:99 + cheat + description:Die after one hit + code:7E215A:00 + +cartridge sha256:056ac8160363d577e3ffc2f593801b8bb3d024fe4f3a3331b711dc556204949d + title:Super Turrican (USA) + cheat + description:Invincibility + code:C226-DDD4 + cheat + description:Infinite time + code:6D28-ADDF + cheat + description:Infinite lives + code:C22D-ADDF + cheat + description:Infinite continues + code:C266-DD6F + cheat + description:Infinite wheel time + code:C22D-0404 + cheat + description:Infinite Smart Lines + code:C226-D704 + cheat + description:Don't decrease weapon power after dying + code:6D22-640F+F122-646F + cheat + description:Never change weapon type + code:4A82-AF0D + cheat + description:Start with blue weapon + code:DF83-6D0D + cheat + description:Start with yellow weapon + code:D483-6D0D + cheat + description:Start with all weapons at maximum power (4 power-ups) + code:D083-6D0D+BA83-67DD + cheat + description:Start with 1 life - Normal/Hard only + code:DD61-6D0D + cheat + description:Start with 2 lives - Normal/Hard only + code:DF61-6D0D + cheat + description:Start with 5 lives - Normal/Hard only + code:D061-6D0D + cheat + description:Start with 10 lives - Normal/Hard only + code:DB61-6D0D + cheat + description:Start with 25 lives - Normal/Hard only + code:F661-6D0D + cheat + description:Start with 50 lives - Normal/Hard only + code:7F61-6D0D + cheat + description:Start with 99 lives - Normal/Hard only + code:1461-6D0D + cheat + description:Start with 1 continue - Easy/Normal only + code:DF6F-6DDD + cheat + description:Start with 2 continues - Easy/Normal only + code:D46F-6DDD + cheat + description:Start with 5 continues - Easy/Normal only + code:D96F-6DDD + cheat + description:Start with 10 continues - Easy/Normal only + code:DC6F-6DDD + cheat + description:Start with 25 continues - Easy/Normal only + code:FB6F-6DDD + cheat + description:Start with 50 continues - Easy/Normal only + code:746F-6DDD + cheat + description:Start with 99 continues - Easy/Normal only + code:176F-6DDD + cheat + description:Start with no Smart Lines + code:DD8E-6DDD + cheat + description:Start with 1 Smart Line + code:DF8E-6DDD + cheat + description:Start with 2 Smart Lines + code:D48E-6DDD + cheat + description:Start with 4 Smart Lines - only 3 shown at once + code:D08E-6DDD + cheat + description:Start with 5 Smart Lines - only 3 shown at once + code:D98E-6DDD + cheat + description:Start with 10 Smart Lines - only 3 shown at once + code:DC8E-6DDD + cheat + description:Start with 25 Smart Lines - only 3 shown at once + code:FB8E-6DDD + cheat + description:Start with 50 Smart Lines - only 3 shown at once + code:748E-6DDD + cheat + description:Start with 99 Smart Lines - only 3 shown at once + code:178E-6DDD + cheat + description:Start on level 2 + code:D46D-64DD + cheat + description:Start on level 3 + code:D76D-64DD + cheat + description:Start on level 4 + code:D06D-64DD + cheat + description:Start on level 5 + code:D96D-64DD + cheat + description:Start on level 6 + code:D16D-64DD + cheat + description:Start on level 7 + code:D56D-64DD + cheat + description:Start on level 8 + code:D66D-64DD + cheat + description:Start on level 9 + code:DB6D-64DD + cheat + description:Start on level 10 + code:DC6D-64DD + cheat + description:Start on level 11 + code:D86D-64DD + cheat + description:Start on level 12 + code:DA6D-64DD + cheat + description:Start on level 13 + code:7E049E:0D + cheat + description:Infinite health + code:7E04FF:0C + cheat + description:Infinite time (alt) + code:7E056C:23 + cheat + description:Infinite Bombs + code:7E050A:04 + +cartridge sha256:96da3512a1aa05a40f1e5d61c48932b0d55d9f136d6418b848153a9fecab06de + title:Super Turrican 2 (USA) + cheat + description:Infinite time + code:7E0AEA:03+7E0AEB:55 + cheat + description:Infinite lives + code:7E0AF2:02 + cheat + description:Infinite Bombs + code:7E0AF4:03 + cheat + description:Have Missile sub-weapon + code:7E034A:01 + cheat + description:Max Spread Shot level + code:7E033C:04 + cheat + description:Max Rebound level + code:7E033E:04 + cheat + description:Max Laser level + code:7E0340:04 + cheat + description:Max Flamethrower level + code:7E0342:04 + cheat + description:Start with Spread Shot + code:7E0336:00 + cheat + description:Start with Rebound + code:7E0336:10 + cheat + description:Start with Laser + code:7E0336:16 + cheat + description:Start with Flamethrower + code:7E0336:02 + cheat + description:Start on level 2 + code:7E007E:02 + cheat + description:Start on level 3 + code:7E007E:03 + cheat + description:Start on level 4 + code:7E007E:04 + cheat + description:Start on level 5 + code:7E007E:05 + cheat + description:Start on level 6 + code:7E007E:06 + cheat + description:Start on level 7 + code:7E007E:07 + cheat + description:Start on level 8 + code:7E007E:08 + cheat + description:Start on level 9 + code:7E007E:09 + cheat + description:Start on level 10 + code:7E007E:0A + cheat + description:Start on level 11 + code:7E007E:0B + cheat + description:Start on level 12 + code:7E007E:0C + cheat + description:Start on level 13 + code:7E007E:0E + cheat + description:Start on level 14 + code:7E007E:0F + cheat + description:Start on level 15 + code:7E007E:10 + cheat + description:Start on level 16 + code:7E007E:11 + cheat + description:Start on level 17 + code:7E007E:12 + +cartridge sha256:792e615a34ceae5a1b9a4f54c5a5d9b53e39299332fece83e4bceca2c22efb21 + title:Super Valis IV (USA) + cheat + description:Allows you to select easy mode on the options screen + code:042C-ADD7 + cheat + description:Infinite usage for all special attacks + code:DD66-A7A7 + cheat + description:Protection from most enemy attacks + code:C2AA-0DAF + cheat + description:Infinite hits on armor + code:C2AA-0FAF + cheat + description:Heart worth more + code:F684-0F0D + cheat + description:Heart worth much more + code:4684-0F0D + cheat + description:Selecting an item does not remove it from the menu of available items + code:826F-A467 + cheat + description:Enables level select + code:3CAC-6407 + cheat + description:Get any score for maximum score + code:DDCB-D7A7 + cheat + description:Item is always search + code:CB62-6767+D762-67A7 + cheat + description:Item is always three-way beam + code:CB62-6767+DF62-67A7 + cheat + description:Item is always bomber + code:CB62-6767+D462-67A7 + cheat + description:Item is always homing + code:CB62-6767+D062-67A7 + cheat + description:Item is always heart + code:CB62-6767+D962-67A7 + cheat + description:Item is always armor + code:CB62-6767+D162-67A7 + cheat + description:Infinite max health + code:7E0FB5:40 + cheat + description:Highest max health + code:7E0FB6:40 + cheat + description:Infinite item use + code:7E0FAE:09 + cheat + description:Have all items + code:7E0FA7:01+7E0FA8:02+7E0FA9:03+7E0FAA:04+7E0FAB:05+7E0FAC:06 + +cartridge sha256:62d3d650e956f23f3b221f83c5c5bd204afd0e4f4d9c47a3251962323de96089 + title:Super Widget (USA) + cheat + description:Invincibility + code:DDB9-0F0D + cheat + description:Infinite lives + code:C268-AFDD + cheat + description:Infinite time + code:C26B-6D6D + cheat + description:1 W gives 1 life + code:D7BA-D4D7 + +cartridge sha256:d802715fb4f09d7e499b5b3e577af641598a723dae7cedeaa93943bb53c6edbb + title:SWAT Kats - The Radical Squadron (USA) + cheat + description:Invincibility after first hit + code:829F-EDAD + cheat + description:Invincible while flying the jet + code:18EB-5FD9+18E2-5FA9+18ED-84A9 + cheat + description:Almost infinite health + code:70A9-7467 + cheat + description:Gain levels quickly + code:1B71-5DD5 + cheat + description:World 5 - Dark Kat always enabled + code:D932-7F67 + +cartridge sha256:c2015d03dd3db08069b2a6ea1ed6b3e1ac1e3a5f804b02295c3cd3717add91ef + title:Syndicate (USA) + cheat + description:Start with Mega-cash + code:7DC3-1FDD+7DC3-1F0D + cheat + description:All agents have infinite ammo for pistols + code:CBAB-CD01 + +cartridge sha256:365f10f9d9f68cc59e769eeb451c417e1ff7415022a625de9976a3b924c0bd61 + title:T2 - The Arcade Game (USA) + cheat + description:Infinite health (alt) - P1 + code:6D33-47D6 + cheat + description:Infinite health (alt) - P2 + code:6D3F-1DA6 + cheat + description:Infinite gunpower - P1 + code:C9B7-1407 + cheat + description:Infinite gunpower - P2 + code:C9B9-17D7 + cheat + description:Infinite missiles - P1 + code:DD2A-476B + cheat + description:Infinite missiles - P2 + code:DD2E-4DDB + cheat + description:Shields lasts longer + code:5E27-44A7 + cheat + description:Plasma Pulse Energizer lasts longer - P1 + code:D62B-4F67 + cheat + description:Plasma Pulse Energizer lasts longer - P2 + code:D628-47D7 + cheat + description:Keep P.P.E. for that level once picked up - P1 + code:C267-47A5 + cheat + description:Keep P.P.E. for that level once picked up - P2 + code:C260-4765 + cheat + description:Get 6 missiles for each 1 - P1 + code:D12D-4707 + cheat + description:Get 9 missiles for each 1 - P1 + code:DB2D-4707 + cheat + description:Get 9 missiles for each 1 - P2 + code:D124-4D67 + cheat + description:Get 6 missiles for each 1 - P2 + code:DB24-4D67 + cheat + description:Gunpower replenishes slower - P1 + code:FDB3-476F + cheat + description:Gunpower replenishes slower - P2 + code:FDB0-1F0F + cheat + description:10 credits + code:FD3E-C7A3 + cheat + description:15 credits + code:F93E-C7A3 + cheat + description:20 credits + code:4D3E-C7A3 + cheat + description:P.P.E. does extra damage - P1 + code:D12B-44A7 + cheat + description:P.P.E. does massive damage - P1 + code:F42B-44A7 + cheat + description:Infinite health - P1 + code:7E007F:7F + cheat + description:Infinite health - P2 + code:7E0081:7F + +cartridge sha256:1711fe9010232b41ec406900e5b4ef528dd2beaa97b27d94ed7eef57d63904a0 + title:Taz-Mania (USA) (Rev 1) + cheat + description:Infinite health + code:C935-40C0 + cheat + description:Infinite time + code:DD3B-C0C0 + cheat + description:Infinite continues (don't combine with start on act codes) + code:C238-1140 + cheat + description:Advance to next level after getting 1 kiwi + code:6089-319C + cheat + description:Faster timer + code:D035-C540 + cheat + description:1 minute to complete act 1, level 1 + code:DF64-41C0 + cheat + description:5 minutes to complete act 1, level 1 + code:D964-41C0 + cheat + description:Kiwi's worth 2 + code:E389-319C + cheat + description:Kiwi's worth 4 + code:EA89-319C + cheat + description:Kiwi's worth 5 + code:E889-319C + cheat + description:Kiwi's worth 7 + code:EB89-319C + cheat + description:Red bird worth 0 seconds instead of 10 + code:DD30-C910 + cheat + description:Red bird worth 20 seconds + code:D430-C910 + cheat + description:Red bird worth 30 seconds + code:D730-C910 + cheat + description:Red bird worth 40 seconds + code:D030-C910 + cheat + description:Red bird worth 50 seconds + code:D930-C910 + cheat + description:Start with 1/4 normal health + code:D522-3545 + cheat + description:Start with 1/2 normal health + code:DE22-3545 + cheat + description:Start with 3/4 normal health + code:F922-3545 + cheat + description:Start with 1 continue (don't combine with start on act codes) + code:DF3F-15C0 + cheat + description:Start with 5 continues (don't combine with start on act codes) + code:D93F-15C0 + cheat + description:Start with 7 continues (don't combine with start on act codes) + code:D53F-15C0 + cheat + description:Start with 9 continues (don't combine with start on act codes) + code:DB3F-15C0 + cheat + description:Start with 50 continues (don't combine with start on act codes) + code:743F-15C0 + cheat + description:Start with 99 continues (don't combine with start on act codes) + code:173F-15C0 + cheat + description:Start on act 1, level 2 + code:4A36-1140+7D36-1110+DF3F-15C0 + cheat + description:Start on act 1, level 3 + code:4A36-1140+7D36-1110+D43F-15C0 + cheat + description:Start on act 1 bonus level + code:4A36-1140+7D36-1110 + cheat + description:Start on act 2, level 1 + code:4A36-1140+7D36-1110+D03F-15C0 + cheat + description:Start on act 2, level 2 + code:4A36-1140+7D36-1110+D93F-15C0 + cheat + description:Start on act 2, level 3 + code:4A36-1140+7D36-1110+D13F-15C0 + cheat + description:Start on act 2 bonus level + code:4A36-1140+7D36-1110+D53F-15C0 + cheat + description:Start on act 3, level 1 + code:4A36-1140+7D36-1110+D63F-15C0 + cheat + description:Start on act 3, level 2 + code:4A36-1140+7D36-1110+DB3F-15C0 + cheat + description:Start on act 3, level 3 + code:4A36-1140+7D36-1110+DC3F-15C0 + cheat + description:Start on act 3 bonus level + code:4A36-1140+7D36-1110+D83F-15C0 + cheat + description:Start on act 4, level 1 + code:4A36-1140+7D36-1110+DA3F-15C0 + cheat + description:Start on act 4, level 2 + code:4A36-1140+7D36-1110+D23F-15C0 + cheat + description:Start on act 4, level 3 + code:4A36-1140+7D36-1110+D33F-15C0 + cheat + description:Start on act 4 bonus level + code:4A36-1140+7D36-1110+DE3F-15C0 + cheat + description:Start on act 5, level 1 + code:4A36-1140+7D36-1110+FD3F-15C0 + cheat + description:Start on act 5, level 2 + code:4A36-1140+7D36-1110+FF3F-15C0 + cheat + description:Start on act 5, level 3 + code:4A36-1140+7D36-1110+F43F-15C0 + cheat + description:Infinite health (alt) + code:7E0096:1D + cheat + description:Infinite time (alt) + code:7E0098:99 + +cartridge sha256:e3bd2296b860a547bb8594485048d3e1326a416405ed9e91139c75f8927acfe3 + title:Taz-Mania (USA) + cheat + description:Infinite health + code:C935-40C0 + cheat + description:Infinite time + code:DD3B-C0C0 + cheat + description:Infinite continues (don't combine with start on act codes) + code:C238-1140 + cheat + description:Advance to next level after getting 1 kiwi + code:6089-319C + cheat + description:Faster timer + code:D035-C540 + cheat + description:1 minute to complete act 1, level 1 + code:DF64-41C0 + cheat + description:5 minutes to complete act 1, level 1 + code:D964-41C0 + cheat + description:Kiwi's worth 2 + code:E389-319C + cheat + description:Kiwi's worth 4 + code:EA89-319C + cheat + description:Kiwi's worth 5 + code:E889-319C + cheat + description:Kiwi's worth 7 + code:EB89-319C + cheat + description:Red bird worth 0 seconds instead of 10 + code:DD30-C910 + cheat + description:Red bird worth 20 seconds + code:D430-C910 + cheat + description:Red bird worth 30 seconds + code:D730-C910 + cheat + description:Red bird worth 40 seconds + code:D030-C910 + cheat + description:Red bird worth 50 seconds + code:D930-C910 + cheat + description:Start with 1/4 normal health + code:D522-3545 + cheat + description:Start with 1/2 normal health + code:DE22-3545 + cheat + description:Start with 3/4 normal health + code:F922-3545 + cheat + description:Start with 1 continue (don't combine with start on act codes) + code:DF3F-15C0 + cheat + description:Start with 5 continues (don't combine with start on act codes) + code:D93F-15C0 + cheat + description:Start with 7 continues (don't combine with start on act codes) + code:D53F-15C0 + cheat + description:Start with 9 continues (don't combine with start on act codes) + code:DB3F-15C0 + cheat + description:Start with 50 continues (don't combine with start on act codes) + code:743F-15C0 + cheat + description:Start with 99 continues (don't combine with start on act codes) + code:173F-15C0 + cheat + description:Start on act 1, level 2 + code:4A36-1140+7D36-1110+DF3F-15C0 + cheat + description:Start on act 1, level 3 + code:4A36-1140+7D36-1110+D43F-15C0 + cheat + description:Start on act 1 bonus level + code:4A36-1140+7D36-1110 + cheat + description:Start on act 2, level 1 + code:4A36-1140+7D36-1110+D03F-15C0 + cheat + description:Start on act 2, level 2 + code:4A36-1140+7D36-1110+D93F-15C0 + cheat + description:Start on act 2, level 3 + code:4A36-1140+7D36-1110+D13F-15C0 + cheat + description:Start on act 2 bonus level + code:4A36-1140+7D36-1110+D53F-15C0 + cheat + description:Start on act 3, level 1 + code:4A36-1140+7D36-1110+D63F-15C0 + cheat + description:Start on act 3, level 2 + code:4A36-1140+7D36-1110+DB3F-15C0 + cheat + description:Start on act 3, level 3 + code:4A36-1140+7D36-1110+DC3F-15C0 + cheat + description:Start on act 3 bonus level + code:4A36-1140+7D36-1110+D83F-15C0 + cheat + description:Start on act 4, level 1 + code:4A36-1140+7D36-1110+DA3F-15C0 + cheat + description:Start on act 4, level 2 + code:4A36-1140+7D36-1110+D23F-15C0 + cheat + description:Start on act 4, level 3 + code:4A36-1140+7D36-1110+D33F-15C0 + cheat + description:Start on act 4 bonus level + code:4A36-1140+7D36-1110+DE3F-15C0 + cheat + description:Start on act 5, level 1 + code:4A36-1140+7D36-1110+FD3F-15C0 + cheat + description:Start on act 5, level 2 + code:4A36-1140+7D36-1110+FF3F-15C0 + cheat + description:Start on act 5, level 3 + code:4A36-1140+7D36-1110+F43F-15C0 + cheat + description:Infinite health (alt) + code:7E0096:1D + cheat + description:Infinite time (alt) + code:7E0098:99 + +cartridge sha256:35dd020cf57fc402417ab6e4a6c49866c5a86bba25218c0aaf7ce85cb134bcf8 + title:Tecmo Super Bowl (USA) + cheat + description:Always 1st down + code:C9BA-14DC + cheat + description:1 play to get a 1st down + code:DFBA-170C + cheat + description:2 plays to get a 1st down + code:D4BA-170C + cheat + description:3 plays to get a 1st down + code:D7BA-170C + cheat + description:5 plays to get a 1st down + code:D9BA-170C + cheat + description:7 plays to get a 1st down + code:D5BA-170C + cheat + description:Extra points worth 0 points - P1 + code:DD61-34DC + cheat + description:Extra points worth 3 points - P1 + code:D761-34DC + cheat + description:Extra points worth 5 points - P1 + code:D961-34DC + cheat + description:Extra points worth 9 points - P1 + code:DB61-34DC + cheat + description:Extra points worth 0 points - P2 + code:DDB5-34AB + cheat + description:Extra points worth 3 points - P2 + code:D7B5-34AB + cheat + description:Extra points worth 5 points - P2 + code:D9B5-34AB + cheat + description:Extra points worth 9 points - P2 + code:DBB5-34AB + cheat + description:Field goals worth 0 points - P1 + code:DD63-37AB + cheat + description:Field goals worth 1 points - P1 + code:DF63-37AB + cheat + description:Field goals worth 5 points - P1 + code:D963-37AB + cheat + description:Field goals worth 9 points - P1 + code:DB63-37AB + cheat + description:Field goals worth 0 points - P2 + code:DDBD-4DDB + cheat + description:Field goals worth 1 points - P2 + code:DFBD-4DDB + cheat + description:Field goals worth 5 points - P2 + code:D9BD-4DDB + cheat + description:Field goals worth 9 points - P2 + code:DBBD-4DDB + cheat + description:Safeties worth 0 points - P1 + code:DDB0-17AB + cheat + description:Safeties worth 1 points - P1 + code:DFB0-17AB + cheat + description:Safeties worth 5 points - P1 + code:D9B0-17AB + cheat + description:Safeties worth 9 points - P1 + code:DBB0-17AB + cheat + description:Safeties worth 0 points - P2 + code:DD67-17DC + cheat + description:Safeties worth 1 points - P2 + code:DF67-17DC + cheat + description:Safeties worth 5 points - P2 + code:D967-17DC + cheat + description:Safeties worth 9 points - P2 + code:DB67-17DC + cheat + description:Touchdowns worth 0 points - P1 + code:DD66-14AC + cheat + description:Touchdowns worth 3 points - P1 + code:D766-14AC + cheat + description:Touchdowns worth 5 points - P1 + code:D966-14AC + cheat + description:Touchdowns worth 8 points - P1 + code:D666-14AC + cheat + description:Touchdowns worth 0 points - P2 + code:DDCE-34A8+DDBB-176B + cheat + description:Touchdowns worth 3 points - P2 + code:D7CE-34A8+D7BB-176B + cheat + description:Touchdowns worth 5 points - P2 + code:D9CE-34A8+D9BB-176B + cheat + description:Touchdowns worth 9 points - P2 + code:DBCE-34A8+DBBB-176B + cheat + description:0 timeouts for the first half - both players + code:DDA5-1F2D + cheat + description:2 timeouts for the first half - both players + code:D4A5-1F2D + cheat + description:7 timeouts for the first half - both players + code:D5A5-1F2D + cheat + description:9 timeouts for the first half - both players + code:DBA5-1F2D + cheat + description:0 timeouts for the first half - P1 + code:10A5-14FD + cheat + description:0 timeouts for the first half - P2 + code:10A5-14BD + cheat + description:0 timeouts for the second half - both players + code:DDAA-14FD + cheat + description:2 timeouts for the second half - both players + code:D4AA-14FD + cheat + description:7 timeouts for the second half - both players + code:D5AA-14FD + cheat + description:9 timeouts for the second half - both players + code:DBAA-14FD + cheat + description:0 timeouts for the second half - P1 + code:10AA-149D + cheat + description:0 timeouts for the second half - P2 + code:10AA-142D + cheat + description:Timeouts are not reset at half-time - P1 + code:C9AA-149D + cheat + description:Timeouts are not reset at half-time - P2 + code:C9AA-142D + cheat + description:Quarters start at 2 minutes 30 seconds + code:7DB3-C705+D4B3-C765 + +cartridge sha256:8cfd4c5525f4bd4bba5af7e2323f1e61f27ce97c6d5617cfa685c9276fbf6407 + title:Tecmo Super Bowl III - Final Edition (USA) + cheat + description:Infinite ability points in the edit menu + code:3C38-C25D + +cartridge sha256:5b82cdd6f2da56f43680d6a5021faebe2e06036d30602c1a7917aa414cf8b5f4 + title:Teenage Mutant Ninja Turtles IV - Turtles in Time (USA) + cheat + description:Invincibility + code:3C86-0764+B98B-0D64+CB86-07A4+D48B-0DD4+DD8B-0D04 + cheat + description:Infinite health + code:892F-0DD7 + cheat + description:Infinite lives + code:DDAC-6F67 + cheat + description:One hit kills (disable during Shredder's first fight) + code:6D6C-0F2F + cheat + description:Hit anywhere - P1 + code:EA66-67AA + cheat + description:Hit anywhere - P2 + code:EA6B-67AA + cheat + description:Start with 1 life instead of 3 + code:DD28-67D9 + cheat + description:Start with 5 lives + code:D028-67D9 + cheat + description:Start with 10 lives + code:DB28-67D9 + cheat + description:Start with 25 lives + code:4028-67D9 + cheat + description:Start with 50 lives + code:0B28-67D9 + cheat + description:Start with 75 lives + code:5028-67D9 + cheat + description:Start with 100 lives + code:BB28-67D9 + cheat + description:Start on level 2 + code:69B8-A42F+6FB8-A7FF+DDB8-A79F+DFB8-A4BF + cheat + description:Start on level 4 + code:69B8-A42F+6FB8-A7FF+DDB8-A79F+D7B8-A4BF + cheat + description:Start on level 5 + code:69B8-A42F+6FB8-A7FF+DDB8-A79F+D0B8-A4BF + cheat + description:Start on level 6 + code:69B8-A42F+6FB8-A7FF+DDB8-A79F+D9B8-A4BF + cheat + description:Start on level 7 + code:69B8-A42F+6FB8-A7FF+DDB8-A79F+D1B8-A4BF + cheat + description:Start on level 8 + code:69B8-A42F+6FB8-A7FF+DDB8-A79F+D5B8-A4BF + cheat + description:Start on level 9 + code:69B8-A42F+6FB8-A7FF+DDB8-A79F+D6B8-A4BF + cheat + description:Start on level 10 + code:69B8-A42F+6FB8-A7FF+DDB8-A79F+DBB8-A4BF + cheat + description:Infinite health (alt) (enable after level starts) + code:7E044A:56 + +cartridge sha256:849141370f164d6db3e5709da670726f958ce13ffef69319564db3fb0b12c69d + title:Teenage Mutant Ninja Turtles - Tournament Fighters (USA) + cheat + description:Health doesn't decrease over time + code:DDC1-1D03 + cheat + description:Automatic and infinite continues + code:82A6-4FA4 + cheat + description:Hit anywhere - P1 + code:6D69-149F + cheat + description:Hit anywhere - P2 + code:6D6f-1F9F + cheat + description:Leonardo is replaced by Rat King + code:DCCA-1405 + cheat + description:Leonardo is replaced by Karai + code:D8CA-1405 + cheat + description:Raphael is replaced by Rat King + code:DCCA-14A5 + cheat + description:Raphael is replaced by Karai + code:D8CA-14A5 + cheat + description:Donatello is replaced by Rat King + code:DCCA-1705 + cheat + description:Donatello is replaced by Karai + code:D8CA-1705 + cheat + description:Matches are 10 seconds long (leave menu option on 60) + code:FD86-4F00 + cheat + description:Matches are 15 seconds long (leave menu option on 60) + code:F986-4F00 + cheat + description:Matches are 20 seconds long (leave menu option on 60) + code:4D86-4F00 + cheat + description:Matches are 75 seconds long (leave menu option on 60) + code:5986-4F00 + cheat + description:Ultimate attack can be done any time + code:DFCA-44A3 + cheat + description:Ultimate attack can be done with about 1/4 health + code:F0CA-44A3 + cheat + description:Ultimate attack can be done with about 1/2 health + code:46CA-44A3 + cheat + description:Ultimate attack can be done with about 3/4 health + code:7ACA-44A3 + cheat + description:Health decreases twice as fast + code:D4C1-1D03 + cheat + description:After doing an ultimate attack, health bar goes to about 1/4 + code:F0C3-4463 + cheat + description:After doing an ultimate attack, health bar goes to about 1/2 + code:46C3-4463 + cheat + description:After doing an ultimate attack, health bar goes to about 3/4 + code:7AC3-4463 + cheat + description:Start with 1/4 health - both players + code:F6E9-3D25 + cheat + description:Start with 1/2 health - both players + code:7DE9-3D25 + cheat + description:Start with 3/4 health - both players + code:06E9-3D25 + cheat + description:Start with no continues (leave menu option on 3) + code:DDB1-CF60 + cheat + description:Start with 1 continue + code:D4B1-CF60 + cheat + description:Start with 3 continues + code:D0B1-CF60 + cheat + description:Start with 5 continues + code:D1B1-CF60 + cheat + description:Start with 7 continues + code:D6B1-CF60 + +cartridge sha256:8620203da71d32d017bb21f542864c1d90705b87eb67815d06b43f09120318aa + title:Tengai Makyou Zero (Japan) + cheat + description:No random battles + code:7E1659:08 + cheat + description:Infinite HP - character 1 + code:7E1694:E7+7E1695:03 + cheat + description:Infinite HP - character 2 + code:7E1696:E7+7E1697:03 + cheat + description:Infinite HP - character 3 + code:7E1698:E7+7E1699:03 + cheat + description:Infinite MP - character 1 + code:7E16C8:E7+7E16C9:03 + cheat + description:Infinite MP - character 2 + code:7E16CA:E7+7E16CB:03 + cheat + description:Infinite MP - character 3 + code:7E16CC:E7+7E16CD:03 + cheat + description:Fast level gain + code:7E1950:FF+7E1951:FF + +cartridge sha256:bd7074ef4a05d790646abe145ffd2587fb48044e4b730286d807abe102841177 + title:Terminator, The (USA) + cheat + description:Infinite lives (not on car stages) + code:C286-17DD + cheat + description:Infinite Grenades + code:4AA3-0F96 + cheat + description:Infinite Missiles + code:C2A5-0D98 + cheat + description:10 Grenades on pick-up + code:DCAB-A7FC + cheat + description:2 Grenades on pick-up + code:D4AB-A7FC + cheat + description:Longer invulnerability after being hit + code:EE81-0D9C + cheat + description:Shorter invulnerability after being hit + code:FE81-0D9C + cheat + description:Don't lose Grenades on dying + code:4AA9-04F6 + cheat + description:Don't lose Missiles on dying + code:4AA9-0F96 + cheat + description:Get Rapid Fire on dying + code:D7A9-0D96 + cheat + description:Start with Rapid Fire + code:D767-CFAD + cheat + description:Start with 9 lives + code:DBA2-C4AF + cheat + description:Start with 1 life + code:DFA2-C4AF + +cartridge sha256:06db3be569a587d79b51bfc684fd2ebdea977863875aedec88218fbb4169c21b + title:Terminator 2 - Judgment Day (USA) + cheat + description:Infinite energy + code:7E1407:C8 + cheat + description:Infinite health - John + code:7E1452:64 + cheat + description:Infinite health - Sarah + code:7E149D:64 + cheat + description:Infinte ammo + code:7E1407:FF + +cartridge sha256:3cdebbd8adc4bb6773a7995f542fdac49adefca71cba583255a1c1bf37ac3946 + title:Tetris & Dr. Mario (USA) + cheat + description:Tetris - Level never increases + code:6DB4-1F65 + cheat + description:Tetris - After the first level your level increases every line + code:DFB4-1405 + cheat + description:Tetris - The same piece always drops + code:CBB7-C460+D4B7-C4A0+DDB7-C7D0 + cheat + description:Tetris - Always at high speed + code:CBB2-3DA9+DCB2-3FD9+3CB2-3F09 + cheat + description:Dr. Mario - The same piece always drops until you hit the change button + code:CBC9-4466+DCC9-44A6+3CC9-47D6 + cheat + description:Dr. Mario - The same piece always drops + code:CB67-37DC+DC67-370C+3C67-376C + cheat + description:Tetris 2 - Select any round - 1P (at round select meter, keep pressing right) + code:9DBD-3DF4 + cheat + description:Tetris 2 - Tile speed always at 0 + code:CBC5-4FDC+DDC5-4F0C+DDC5-4F6C + cheat + description:Tetris 2 - Tile speed always at 255 + code:CBC5-4FDC+EEC5-4F0C+DDC5-4F6C + cheat + description:Tetris 2 - More time to place the blocks where you want them, even after they hit the ground (left and right only) + code:6DB1-346B + +cartridge sha256:70dea29a928c1625def31c862dc74960e39e587e416b45829efc21f13ebd9630 + title:Tetris 2 (USA) (Rev 1) + cheat + description:Select any round + code:9DBD-3DF4 + cheat + description:Tile speed always at 0 + code:CBC5-4FDC+DDC5-4F0C+DDC5-4F6C + cheat + description:Tile speed always at 255 + code:CBC5-4FDC+EEC5-4F0C+DDC5-4F6C + cheat + description:More time to place the blocks where you want them + code:6DB1-346B + +cartridge sha256:accc836c3adabadc810fbe35702c6a64d50a09f4c672d2734fa58b251d7a20aa + title:Tetris 2 (USA) + cheat + description:Select any round + code:9DBD-3DF4 + cheat + description:Tile speed always at 0 + code:CBC5-4FDC+DDC5-4F0C+DDC5-4F6C + cheat + description:Tile speed always at 255 + code:CBC5-4FDC+EEC5-4F0C+DDC5-4F6C + cheat + description:More time to place the blocks where you want them + code:6DB1-346B + +cartridge sha256:4aee5b05ae11643fc6cb7ed32dfd4e82bbb52d03b12aabb080af35e2df6f562f + title:Tetsuwan Atom (Japan) + cheat + description:Invincibility + code:2D65-C05D + cheat + description:Infinite health + code:C2CF-4D61 + cheat + description:Infinite lives + code:C2C1-1409 + +cartridge sha256:d50aaa41e153ca356eee16a9deccb1a763ee56ebbe6c80cd28c5ad1db66a5316 + title:Thunder Spirits (USA) + cheat + description:Infinite lives + code:CBCC-0407 + cheat + description:Infinite lives (alt) + code:C2CC-5407 + cheat + description:Infinite credits + code:3CAC-67DF + cheat + description:Infinite credits (alt) + code:C2A8-8D0F + cheat + description:Keep captured weapon until game ends (except claw and shield) + code:C2C8-0407+C2C8-0767 + cheat + description:Continue with 1 life + code:BAAD-ADDF + cheat + description:Continue with 2 lives + code:DDAE-670F+CBAE-67DF + cheat + description:Continue with 5 lives + code:D7AE-670F+CBAE-67DF + cheat + description:Continue with 7 lives + code:D9AE-670F+CBAE-67DF + cheat + description:Continue with 9 lives + code:D5AE-670F+CBAE-67DF + cheat + description:Start with 1 credit + code:C7BF-0DAD + cheat + description:Start with 2 credits + code:84BF-0DAD + cheat + description:Start with 3 credits + code:B4BF-0DAD + cheat + description:Start with 5 credits + code:BEBF-0DAD + cheat + description:Start with 8 credits + code:68BF-0D6D+C4BF-0DAD + cheat + description:Start with 12 credits + code:D0BF-0D6D+C3BF-0DAD + cheat + description:Start with 1 life + code:EEB3-DD0D+CBB3-DDDD + cheat + description:Start with 2 lives + code:DDB3-DD0D+CBB3-DDDD + cheat + description:Start with 5 lives + code:D7B3-DD0D+CBB3-DDDD + cheat + description:Start with 7 lives + code:D9B3-DD0D+CBB3-DDDD + cheat + description:Start with 9 lives + code:D5B3-DD0D+CBB3-DDDD + cheat + description:Start with 25 lives + code:F5B3-DD0D+CBB3-DDDD + cheat + description:Start with 50 lives + code:7DB3-DD0D+CBB3-DDDD + cheat + description:Start with 100 lives + code:14B3-DD0D+CBB3-DDDD + cheat + description:Stage modifier + code:7E1A98:?? + cheat + description:Start on stage 2 + code:DF65-67D4+CB65-64A4+DD65-6704+3C65-6764 + cheat + description:Start on stage 3 + code:D465-67D4+CB65-64A4+DD65-6704+3C65-6764 + cheat + description:Start on stage 4 + code:D765-67D4+CB65-64A4+DD65-6704+3C65-6764 + cheat + description:Start on stage 5 + code:D065-67D4+CB65-64A4+DD65-6704+3C65-6764 + cheat + description:Start on stage 6 + code:D965-67D4+CB65-64A4+DD65-6704+3C65-6764 + cheat + description:Start on stage 7 + code:D165-67D4+CB65-64A4+DD65-6704+3C65-6764 + cheat + description:Start on stage 8 + code:D565-67D4+CB65-64A4+DD65-6704+3C65-6764 + cheat + description:Invincibility + code:7E0418:7B + cheat + description:Invincibility (alt) + code:00AD90:77 + +cartridge sha256:eb958801fd1f08771e5a0933f7701d633262efbfe8d47de21dda18e3b77670de + title:Tick, The (USA) + cheat + description:Infinite lives + code:DDC7-1F6F + cheat + description:Most kicks are stronger + code:DA60-1352 + cheat + description:Most kicks kill most enemies + code:FE60-1352 + +cartridge sha256:8e82f98d2e62bc1e5fcf2386c2b5ca54998398220efcedd67858aaaa92289a42 + title:Time Slip (USA) + cheat + description:Invincibility + code:3CC2-D769 + cheat + description:Infinite health + code:C2B7-6DD0 + cheat + description:Infinite lives + code:C22E-04A7 + cheat + description:Infinite ammo + code:C2C3-AFD0 + cheat + description:Infinite TGS meter + code:C284-A409 + cheat + description:Keep gun power-ups after dying + code:CD24-67A7+CD24-6467 + cheat + description:Flash 2x longer when hit + code:6DB7-6460 + cheat + description:Barely flash at all when hit + code:FDB7-6460 + cheat + description:Fewer enemies + code:C26F-6FD1+C26C-07A1+C26F-ADD1+C26C-0FA1 + cheat + description:Start with all weapons and 9 rounds + code:DB68-6D0D + cheat + description:Start with 16 lives + code:EE6B-670D + cheat + description:Start with 4 health bars - after 1st life + code:DE2E-0F67 + cheat + description:Start with 3 health bars - after 1st life + code:D52E-0F67 + cheat + description:Start with 4 health bars - 1st life + code:DE6C-6F0D + cheat + description:Start with 3 health bars - 1st life + code:D56C-6F0D + cheat + description:Start on stage - Cretaceous + code:CB24-D707+DD24-D7A7+6227-DDD7+DF24-D767 + cheat + description:Start on stage - Egypt + code:CB24-D707+DD24-D7A7+6227-DDD7+D424-D767 + cheat + description:Start on stage - Rome + code:CB24-D707+DD24-D7A7+6227-DDD7+D724-D767 + cheat + description:Start on stage - Invasion 2147 + code:CB24-D707+DD24-D7A7+6227-DDD7+D024-D767 + cheat + description:Start on stage - Tirmat + code:CB24-D707+DD24-D7A7+6227-DDD7+D924-D767 + +cartridge sha256:fa7e2b40093f0cc7233cc77e95bbbea2144c8183dec10446590396fffd7cda37 + title:Time Trax (USA) + cheat + description:Infinite health + code:C2E8-1F60 + cheat + description:Infinite lives + code:C2EF-3FD0 + cheat + description:Invincibility + code:84E948:FF+8187FF:FF + cheat + description:Infinite health (alt) + code:7E14B5:06 + cheat + description:Infinite Time Stall + code:7E14B9:30 + +cartridge sha256:16fb965130e57f37dda2466f23820f091f8b96758aa7e30ba4fd63cb618e5ddb + title:Timecop (USA) + cheat + description:Invincibility + code:DDBA-C4D7 + cheat + description:Don't flash when invincible + code:6DB2-CD07 + cheat + description:Infinite health + code:7E06F3:99 + cheat + description:Infinite Gun + code:7E06F5:99 + cheat + description:Infinite Bombs + code:7E06F7:99 + cheat + description:Infinite time + code:7E0638:63 + +cartridge sha256:0503cd93b4d211a825acd47ff3813668b4ce68890c8be2fbfe5ac2b46882dfcf + title:Tin Star (USA) + cheat + description:Infinite health + code:7E09C8:A0 + cheat + description:Infinite lives + code:7E0928:09 + cheat + description:Bosses die automatically + code:7E0B78:00 + cheat + description:Gain money much faster + code:7E182A:50+7E182B:C3 + cheat + description:Max money + code:7E07DD:09+7E07DC:09+7E07DB:09+7E07DA:09+7E07D9:09+7E07D8:09 + cheat + description:Have $9,000,000 + code:7E07D8:09 + +cartridge sha256:5b8a7309910ae040b6301bdc0ad09fa1991b2b7210a6b76931cd91ce0c82c424 + title:Tinhead (Europe) (Proto) + cheat + description:Infinite health + code:C2BD-DDA4 + cheat + description:Infinite lives + code:C26E-AF6F + cheat + description:Infinite Bombs + code:C2BE-ADDF + +cartridge sha256:71de4dec6a8e8be685627b6e929317f7cefb836997059bbd3b438ccc07a60044 + title:Tintin - Prisoners of the Sun (Europe) (En,Fr,De,Es) + cheat + description:Invincibility + code:2D67-C7DD+2D6B-1D0B + cheat + description:Infinite health + code:A289-376C + cheat + description:Infinite time + code:CE89-C4A8 + cheat + description:Infinite lives + code:A285-37AC + cheat + description:Infinite health (alt) + code:7E059B:04 + cheat + description:Infinite time (alt) + code:7F5B7F:63 + +cartridge sha256:da8b8bccebf51b70213adecda37387d1bdb55aeb7bc0805bb1be1cd9b514daf6 + title:Tintin in Tibet (Europe) (En,Fr,De,Nl) + cheat + description:Invincibility (after first hit) + code:7E050F:2C + cheat + description:Infinite health + code:7E05C9:04 + cheat + description:Infinite lives + code:7E05CB:03 + cheat + description:Infinite time + code:7F59AE:06 + +cartridge sha256:ba679a11264e9695895a6c17358a41e8459be06166d056811df9c2738fef3d0d + title:Tiny Toon Adventures - Buster Busts Loose! (USA) + cheat + description:Infinite health (when hit, a fake empty heart appears) + code:3CE9-448A + cheat + description:Infinite lives (except football level) + code:DD34-37D7 + cheat + description:Infinite lives (football level) + code:DDC0-3F07 + cheat + description:Infinite dash meter + code:C927-47AD + cheat + description:Five heart maximum on challenge level + code:D184-C4A1 + cheat + description:1-up gives 2-up (not on mystery weight challenge level, or by collecting stars) + code:D46B-CFAF + cheat + description:Small star worth 2 + code:D43E-C48E + cheat + description:Small star worth 5 + code:D93E-C48E + cheat + description:Small star worth 10 + code:FD3E-C48E + cheat + description:Gold Gogo Dodo Trophy lasts 1/2 as long + code:DF64-14AA + cheat + description:Gold Gogo Dodo Trophy lasts 2x as long + code:D064-14AA + cheat + description:Choose bonus level after completing a level + code:C9CE-1F0F + cheat + description:Passwords work on any difficulty level (not just Children level) + code:7036-C001 + cheat + description:Continue with 1 life + code:DFC0-CFAF + cheat + description:Continue with 5 lives + code:D9C0-CFAF + cheat + description:Continue with 10 lives + code:FDC0-CFAF + cheat + description:Continue with 25 lives + code:49C0-CFAF + cheat + description:Continue with 50 lives + code:9DC0-CFAF + cheat + description:Continue with 99 lives + code:BBC0-CFAF + cheat + description:Start with 1 life + code:DF6F-14DF + cheat + description:Start with 5 lives + code:D96F-14DF + cheat + description:Start with 10 lives + code:FD6F-14DF + cheat + description:Start with 25 lives + code:496F-14DF + cheat + description:Start with 50 lives + code:9D6F-14DF + cheat + description:Start with 99 lives + code:BB6F-14DF + cheat + description:Start with no continues on normal level - handicap + code:DD6D-47D0 + cheat + description:Start with 7 continues on normal level + code:D56D-47D0 + cheat + description:Start with 9 continues on normal level + code:DB6D-47D0 + cheat + description:Start with no continues on challenge level + code:DD6D-4700 + cheat + description:Start with 5 continues on challenge level + code:D96D-4700 + cheat + description:Start with 7 continues on challenge level + code:D56D-4700 + cheat + description:Start with 9 continues on challenge level + code:DB6D-4700 + cheat + description:Start with 1 heart on Children or Normal difficulty levels (don't pick challenge level) + code:DFCD-4FAF + cheat + description:Start with 4 hearts on Children or Normal difficulty levels, 2 on Challenge + code:D0CD-4FAF + cheat + description:Start with 5 hearts on Children or Normal difficulty levels, 3 on Challenge + code:D9CD-4FAF + +cartridge sha256:08d808e9c5851e4301a38a56b350a20ea9e3adbef51546e87e1785d691d0f2d5 + title:TKO Super Championship Boxing (USA) + cheat + description:Infinite punch meters - both players + code:4088-AF00 + cheat + description:Infinite punch meter - P1 + code:40BF-04DD + cheat + description:Infinite punch meter - P2 + code:40B0-076D + cheat + description:9 minutes per round + code:DB60-A7D4 + cheat + description:6 minutes per round + code:D160-A7D4 + cheat + description:1 minute per round + code:DF60-A7D4 + cheat + description:Allowed only 3 punches in punch meter - P1 + code:D7B4-0D6D+D765-A764 + cheat + description:Allowed only 3 punches in punch meter - P2 + code:D7B9-04DD+D765-A764 + +cartridge sha256:4f500da19dbb1557a7bc0ce14437098c1402478d573fb569303b81c011f86fbf + title:Tom & Jerry (USA) + cheat + description:Invincibility + code:7E14C8:33 + cheat + description:Infinite Hearts + code:7E1242:04 + cheat + description:Infinite lives + code:7E14FC:09 + cheat + description:Infinite time + code:7E157A:63 + cheat + description:Infinite Cheese Bits + code:7E155E:63 + cheat + description:x99 Cheese Bits + code:7E1558:63+7E155C:63 + +cartridge sha256:ca9889f17f184b3d99a2eaaa82af73e366f03ed00313fdd369e5e023b208e788 + title:Top Gear (USA) + cheat + description:Always finish first + code:F6CE-0D6D + cheat + description:Infinite fuel - P1 + code:C225-6429 + cheat + description:Infinite fuel - P2 + code:C223-6D95 + cheat + description:Infinite nitro boosts - P1 + code:3C84-6D64 + cheat + description:Infinite nitro boosts - P2 + code:3C86-64A4 + cheat + description:Nitro boost lasts until end of race - P1 + code:C280-6FA4 + cheat + description:Nitro boost lasts until end of race - P2 + code:C288-6DD4 + cheat + description:Race in any country + code:6DB7-AFEA + cheat + description:Start with 1/2 fuel + code:972B-0F64 + cheat + description:Start with 3/4 fuel + code:5A2B-0F64 + cheat + description:Start with no nitro boosts instead of 3 + code:DD63-6DDD + cheat + description:Start with 1 nitro boost + code:DF63-6DDD + cheat + description:Start with 2 nitro boosts + code:D463-6DDD + cheat + description:Start with 6 nitro boosts + code:D163-6DDD + cheat + description:Start with 9 nitro boosts + code:DB63-6DDD + +cartridge sha256:76b2702c4be8b668c1017f2817c280283c275eaa41535bf6ffa2b8d2220b68c6 + title:Top Gear 2 (USA) + cheat + description:Infinite nitro + code:A267-CD07 + cheat + description:Infinite nitros - P1 + code:C267-CD07 + cheat + description:Infinite nitros - P2 + code:C2CB-CF0F + cheat + description:Infinite fuel + code:C2B7-C404 + cheat + description:Always finish first + code:632E-C767 + cheat + description:Infinite money + code:82C4-49EE + cheat + description:Fuel never runs out + code:C9BD-1F04 + cheat + description:1st place gives $50,000 instead of $10,000 + code:7430-398E + cheat + description:2nd place gives $50,000 instead of $6,000 + code:7430-317E + cheat + description:3rd place gives $50,000 instead of $4,000 + code:7430-318E + cheat + description:4th place gives $50,000 instead of $3,000 + code:7430-357E + cheat + description:5th place gives $50,000 instead of $2,000 + code:7430-358E + cheat + description:6th place gives $50,000 instead of $1,000 + code:7439-307E + cheat + description:7th place gives $50,000 instead of $0 + code:7439-308E + cheat + description:8th place gives $50,000 instead of $0 + code:7439-397E + cheat + description:9th place gives $50,000 instead of $0 + code:7439-398E + cheat + description:10th place gives $50,000 instead of $0 + code:7439-317E + cheat + description:1st place is worth 20 points instead of 10 + code:F039-355A + cheat + description:2nd place is worth 20 points instead of 6 + code:F039-35EA + cheat + description:3rd place is worth 20 points instead of 4 + code:F031-305A + cheat + description:4th place is worth 20 points instead of 3 + code:F031-30EA + cheat + description:5th place is worth 20 points instead of 2 + code:F031-395A + cheat + description:6th place is worth 20 points instead of 1 + code:F031-39EA + cheat + description:7th place is worth 20 points instead of 0 + code:F031-315A + cheat + description:8th place is worth 20 points instead of 0 + code:F031-31EA + cheat + description:9th place is worth 20 points instead of 0 + code:F031-355A + cheat + description:10th place is worth 20 points instead of 0 + code:F031-35EA + cheat + description:Everything is free (must have enough to buy) + code:0BC4-49EE+52C3-3083 + cheat + description:2nd engine costs $1K instead of $30K + code:DFC5-405E + cheat + description:2nd engine costs $15K instead of $30K + code:DEC5-405E + cheat + description:3rd engine costs $1K instead of $50K + code:DFC5-40EE + cheat + description:3rd engine costs $25K instead of $50K + code:FBC5-40EE + cheat + description:4th engine costs $1K instead of $80K + code:DFC5-495E + cheat + description:4th engine costs $40K instead of $80K + code:46C5-495E + cheat + description:2nd wet tires are free + code:DDC5-415E + cheat + description:3rd wet tires are free + code:DDC5-41EE + cheat + description:4th wet tires are free + code:DDC5-455E + cheat + description:2nd dry tires are free + code:DDC6-405E + cheat + description:3rd dry tires are free + code:DDC6-40EE + cheat + description:4th dry tires are free + code:DDC6-495E + cheat + description:2nd gear box costs $1K instead of $10K + code:DFC6-415E + cheat + description:2nd gear box costs $5K instead of $10K + code:D9C6-415E + cheat + description:3rd gear box costs $1K instead of $30K + code:DFC6-41EE + cheat + description:3rd gear box costs $15K instead of $30K + code:DEC6-41EE + cheat + description:4th gear box costs $1K instead of $50K + code:DFC6-455E + cheat + description:4th gear box costs $25K instead of $50K + code:FBC6-455E + cheat + description:2nd nitro costs $1K instead of $5K + code:DFCB-405E + cheat + description:2nd nitro costs $2K instead of $5K + code:D4CB-405E + cheat + description:3rd nitro costs $1K instead of $15K + code:DFCB-40EE + cheat + description:3rd nitro costs $7K instead of $15K + code:D5CB-40EE + cheat + description:4th nitro costs $1K instead of $30K + code:DFCB-495E + cheat + description:4th nitro costs $15K instead of $30K + code:DECB-495E + cheat + description:2nd side armor costs $1K instead of $5K + code:DFCC-405E + cheat + description:2nd side armor costs $2K instead of $5K + code:D4CC-405E + cheat + description:3rd side armor costs $1K instead of $10K + code:DFCC-40EE + cheat + description:3rd side armor costs $5K instead of $10K + code:D9CC-40EE + cheat + description:4th side armor costs $1K instead of $20K + code:DFCC-495E + cheat + description:4th side armor costs $10K instead of $20K + code:DCCC-495E + cheat + description:2nd rear armor costs $1K instead of $5K + code:DFCC-415E + cheat + description:2nd rear armor costs $2K instead of $5K + code:D4CC-415E + cheat + description:3rd rear armor costs $1K instead of $10K + code:DFCC-41EE + cheat + description:3rd rear armor costs $5K instead of $10K + code:D9CC-41EE + cheat + description:4th rear armor costs $1K instead of $20K + code:DFCC-455E + cheat + description:4th rear armor costs $10K instead of $20K + code:DCCC-455E + cheat + description:2nd front armor costs $1K instead of $5K + code:DFC8-405E + cheat + description:2nd front armor costs $2K instead of $5K + code:D4C8-405E + cheat + description:3rd front armor costs $1K instead of $10K + code:DFC8-40EE + cheat + description:3rd front armor costs $5K instead of $10K + code:D9C8-40EE + cheat + description:4th front armor costs $1K instead of $20K + code:DFC8-495E + cheat + description:4th front armor costs $10K instead of $20K + code:DCC8-495E + cheat + description:Start with 0 nitros + code:DD2A-4D6D + cheat + description:Start with 2 nitros + code:D42A-4D6D + cheat + description:Start with 4 nitros + code:D02A-4D6D + cheat + description:Start with 8 nitros + code:D62A-4D6D + cheat + description:Start with 10 nitros + code:DC2A-4D6D + +cartridge sha256:6be49983976564f1fd9eff2f14f5bb41d3a0ff48573e39318088ecce286aca62 + title:Top Gear 3000 (USA) + cheat + description:Always finish first + code:C3EC-1700 + cheat + description:Infinite fuel + code:C936-1D6E + cheat + description:Infinite Nitro + code:A930-3463 + cheat + description:Infinite time + code:7E005B:00 + cheat + description:Infinite money + code:7E0390:75+7E038F:30 + +cartridge sha256:9bf884be5627d38f060ad7f3a61ea1fea1474d416e1d037d33014ca9d5205c1d + title:Total Carnage (USA) + cheat + description:Invincibility + code:6D27-441E + cheat + description:Infinite lives + code:C932-341E + cheat + description:Infinite Time Bombs + code:4029-3F12 + cheat + description:Shields last longer + code:D6B3-C764 + cheat + description:Shields don't last last as long + code:DDB3-C764 + cheat + description:Weapons don't run out until you die or change weapons + code:C930-4D4A + cheat + description:Join in with 2 lives and 3 Time Bombs + code:DFBC-47D4 + cheat + description:Join in with 10 lives and 9 Time Bombs + code:DBBC-47D4 + cheat + description:Start with 2 lives + code:DFC3-44D2 + cheat + description:Start with 10 lives + code:DBC3-44D2 + cheat + description:Start with 1 Time Bomb + code:DFCD-1DD2+40B5-1DD4 + cheat + description:Start with 9 Time Bombs + code:DBCD-1DD2 + cheat + description:Invincibility (alt) + code:8BDC39:80 + cheat + description:Infinite Shield - P1 + code:7E0463:01 + cheat + description:Infinite Shield - P2 + code:7E04AB:01 + cheat + description:Infinite lives - P1 + code:7E0480:09 + cheat + description:Infinite lives - P2 + code:7E04C8:09 + cheat + description:Infinite Time Bombs - P1 + code:7E0481:09 + cheat + description:Infinite Time Bombs - P2 + code:7E04C9:09 + cheat + description:Rapid Fire - P1 + code:7E0477:03 + cheat + description:Rapid Fire - P2 + code:7E04BF:03 + cheat + description:Always have Speed Shoes - P1 + code:7E045E:01+7E0468:01 + cheat + description:Always have Speed Shoes - P2 + code:7E04A6:01+7E04B0:01 + cheat + description:Have normal Gun - P1 + code:7E0476:00 + cheat + description:Have normal Gun - P2 + code:7E04BE:00 + cheat + description:Have Gatling Ball Gun - P1 + code:7E0476:0F + cheat + description:Have Gatling Ball Gun - P2 + code:7E04BE:0F + cheat + description:Have 3-way Gun - P1 + code:7E0476:1E + cheat + description:Have 3-way Gun - P2 + code:7E04BE:1E + cheat + description:Have Rocket Launcher - P1 + code:7E0476:2D + cheat + description:Have Rocket Launcher - P2 + code:7E04BE:2D + cheat + description:Have Blue Flame Thrower - P1 + code:7E0476:4C + cheat + description:Have Blue Flame Thrower - P2 + code:7E04BE:4C + cheat + description:Have Ball Launcher - P1 + code:7E0476:5A + cheat + description:Have Ball Launcher - P2 + code:7E04BE:5A + cheat + description:Have 150 Keys - P1 + code:7E0485:96 + cheat + description:Have 150 Keys - P2 + code:7E04CD:96 + cheat + description:Disable hurry up timer + code:7E00AF:00+7E00B0:00 + +cartridge sha256:345e795000e74f51704774edfc8049473461761a65eb47cab710caa29e09897b + title:Toy Story (USA) + cheat + description:Invincibility + code:C2B7-3914 + cheat + description:Infinite lives + code:CEB9-3914 + cheat + description:Start with 5 more lives than usual + code:D63D-C7BA + cheat + description:Start with 10 more lives than usual + code:DE3D-C7BA + cheat + description:Start with 25 more lives than usual + code:F33D-C7BA + cheat + description:Start with 50 more lives than usual + code:753D-C7BA + cheat + description:Start on level 2 + code:DFA6-3DC4 + cheat + description:Start on level 3 + code:D4A6-3DC4 + cheat + description:Start on level 4 + code:D7A6-3DC4 + cheat + description:Start on level 5 + code:D0A6-3DC4 + cheat + description:Start on level 6 + code:D9A6-3DC4 + cheat + description:Start on level 7 + code:D1A6-3DC4 + cheat + description:Start on level 8 + code:D5A6-3DC4 + cheat + description:Start on level 9 + code:D6A6-3DC4 + cheat + description:Start on level 10 + code:DBA6-3DC4 + cheat + description:Start on level 11 + code:DCA6-3DC4 + cheat + description:Start on level 12 + code:D8A6-3DC4 + cheat + description:Start on level 13 + code:DAA6-3DC4 + cheat + description:Start on level 14 + code:D2A6-3DC4 + cheat + description:Start on level 15 + code:D3A6-3DC4 + cheat + description:Start on level 16 + code:DEA6-3DC4 + cheat + description:Start on level 17 + code:FDA6-3DC4 + +cartridge sha256:7a6e5da46b026900fba4584a32ad40d940b9ecf9fccfb11f96a205a914014784 + title:Toys (USA) + cheat + description:Infinite lives + code:C261-3D7B + cheat + description:Protection against most hazards + code:C2B6-3F5C+C2A4-3F8C + cheat + description:Fewer toys gained from floor boxes + code:DC85-4D34 + cheat + description:More toys gained from floor boxes + code:1EB5-4D34+EEB5-440F + cheat + description:Lots more toys gained from floor boxes + code:7985-4D34+EEB5-440F + cheat + description:Fewer toys gained from carousel + code:DC69-CF47 + cheat + description:More toys gained from carousel + code:7969-CF47 + cheat + description:Lots more toys gained from carousel + code:1E69-CF47 + cheat + description:Start with 1 life + code:DF2D-37AC + cheat + description:Start with 9 lives + code:DB2D-37AC + +cartridge sha256:4070a7702dc506a1ceb6f65b5c330b3a162df6f01735c8f206934fd47b810ed4 + title:Troddlers (USA) + cheat + description:Infinite time + code:C269-6464 + +cartridge sha256:5c7b28bb24bad697156ad444ff23bd15ad6744dbf9899b3cccf2aa36d559d825 + title:True Golf Classics - Pebble Beach Golf Links (USA) + cheat + description:All holes are par 4 + code:CE65-D763 + cheat + description:Course is generally harder (par goes down randomly for some holes) + code:8665-D7A3+D728-04DA + +cartridge sha256:72088194a65fc057f2910945a33d9f071682a4cecac8996f0bdabcdb5ef39962 + title:True Golf Classics - Waialae Country Club (USA) + cheat + description:Most holes have new par values + code:1C6A-67D9+D081-046A + cheat + description:All holes are par 5 + code:CE6A-64A9 + cheat + description:All holes are par 4 + code:CE6A-64A9+1A6A-67D9 + +cartridge sha256:47dd8ea2d12a6bb2a9774de1d492259fc4fb9f8ec7976383bbfd922532671f6b + title:True Lies (USA) + cheat + description:Infinite hand gun shells + code:7E00A5:0F + cheat + description:Infinite big gun shells + code:7E00A9:73 + cheat + description:Infinite Grenades on pick-up + code:7E00AB:03 + cheat + description:Infinite lives + code:7E1A57:05 + +cartridge sha256:8f62d014f513a7dcbca5aa76cbe476c3e4526100f34913af831bc05dab029bd1 + title:Tuff E Nuff (USA) + cheat + description:Invincibility + code:6D6A-14A0 + cheat + description:One hit kills + code:CB67-1FA9+EE67-1409 + cheat + description:Allows you to select same player vs. same player in a 1P vs. 2P game (must select 2nd player using right button) + code:DDAE-CDA5 + cheat + description:Allows you to select any character in a vs. computer game + code:EEA3-C7A1 + cheat + description:Syoh and Zazi's High Fist Thrust does more damage + code:F62E-46F3 + cheat + description:Syoh and Zazi's Sliding Heel Kick does more damage + code:4024-3BF3 + cheat + description:Syoh and Zazi's Big Head Thrust Punch does more damage - from close up only + code:402F-16FE + cheat + description:Syoh and Zazi's Big Head Thrust Punch does no damage + code:DD2F-16FE + cheat + description:Syoh and Zazi's Flying Side Kick does more damage - from close up only + code:4020-CCBE + cheat + description:Syoh and Zazi's Ball of Energy does more damage + code:4030-1B9A + cheat + description:Syoh and Zazi's Palm Hit Drop does more damage + code:4C2E-1B2E + cheat + description:Zazi's Blue Thunder Punch and Syoh's Dragon Blade does more damage + code:403D-3CFA + cheat + description:Kotono's Straight Line Slash does more damage + code:F322-3617 + cheat + description:Kotono's Sweeping Knee Kick does more damage + code:F623-CC17 + cheat + description:Kotono's Flying Swallow Double Drop does more damage + code:F339-3614 + cheat + description:Kotono's Flying Side Kick does more damage + code:F624-3C37 + cheat + description:Kotono's Flying Swallow Point Break does more damage + code:F332-3B44 + cheat + description:Kotono's Drawn Sword Mist Slash does more damage + code:F33E-1C3F + cheat + description:Kotono's Double Edge does more damage + code:F633-3B14 + cheat + description:Kotono's Special Kick does more damage + code:403B-364F + cheat + description:Vortz's Middle Kick does more damage + code:4C3B-4BC9 + cheat + description:Vortz's Low Kick does more damage + code:F630-4B49 + cheat + description:Vortz's Low Aerial Drop Kick does more damage + code:4C3C-3830 + cheat + description:Vortz's Big Double Sledge Hammer does more damage + code:4031-CB10 + cheat + description:Vortz's Diving Knee Pad does more damage + code:F33D-3C30 + cheat + description:Vortz's Diving Elbow does more damage + code:4C3B-CB30 + cheat + description:Vortz's Lightning Tackle does more damage + code:4C30-18C9 + cheat + description:Each round is 80 seconds + code:6D65-14D4 + cheat + description:Each round is 60 seconds + code:1D65-14D4 + cheat + description:Each round is 40 seconds + code:0D65-14D4 + cheat + description:Each round is 20 seconds + code:4D65-14D4 + cheat + description:Start with 1/4 health - P1 + code:F1CE-1FD9 + cheat + description:Start with 1/2 health - P1 + code:4ACE-1FD9 + cheat + description:Start with 3/4 health - P1 + code:04CE-1FD9 + cheat + description:Play stage 2 in story (brings you back to level 1) + code:D066-446F + cheat + description:Play stage 3 in story (brings you back to level 1) + code:D166-446F + cheat + description:Play stage 4 in story (brings you back to level 1) + code:D666-446F + cheat + description:Play stage 5 in story (brings you back to level 1) + code:DC66-446F + cheat + description:Play stage 6 in story (brings you back to level 1) + code:DA66-446F + cheat + description:Play stage 7 in story (brings you back to level 1) + code:D366-446F + cheat + description:Play stage 8 in story (brings you back to level 1) + code:FD66-446F + cheat + description:Play stage 9 in story (brings you back to level 1) + code:F466-446F + cheat + description:Play final stage in story (brings you back to level 1) + code:F066-446F + cheat + description:Infinite health - P1 + code:7E0FB7:58 + cheat + description:Infinite health - P2 + code:7E1010:58 + cheat + description:Infinite time + code:7E0B27:99 + cheat + description:Powered moves - P1 + code:7E0FB8:06 + cheat + description:Powered moves - P2 + code:7E1011:06 + +cartridge sha256:dbf11d4c77b9aa3416f687201d57d71a23bb8fb0b8fe5e9e8212db3fac036631 + title:Turbo Toons (Europe) + cheat + description:Start at Final Tournament (press Select at title screen, then in the topmost menu select the trophy) + code:7E1E44:04 + cheat + description:Infinite Turbo - Hong Kong Phooey + code:7E0C9E:E0 + +cartridge sha256:e4343c0fadc00ffdc3dc31345068d751eea5d639f826731f08cb81673d508c40 + title:Turn and Burn - No-Fly Zone (USA) + cheat + description:Infinite health + code:7E10DB:38 + cheat + description:Infinite fuel + code:7E1AC4:99+7E1AC5:74 + cheat + description:Infinite AIM-7 + code:7E05E9:FF + cheat + description:Infinite AIM-9 + code:7E05E7:FF + cheat + description:Infinite AIM-54 + code:7E05EB:BF + cheat + description:Infinite M-61 + code:7E05E5:FF + +cartridge sha256:c8187417a27a2f14ce2be35eebd0f112bd413b57d3589ae6d40b333bc21ba694 + title:TwinBee - Rainbow Bell Adventure (Japan) + cheat + description:Invincibility + code:7E1994:0A + cheat + description:Infinite health + code:7E02EC:03 + cheat + description:Infinite time + code:7E02CE:00 + +cartridge sha256:259c25d4613f97f5fa7992900fb583625d7fb912c7ae09fa9def2e682834dc9f + title:Twisted Tales of Spike McFang, The (USA) + cheat + description:Invincibility + code:CEA5-34DF + cheat + description:Infinite money + code:C260-3766 + cheat + description:Infinite HP + code:7E4CE0:FF+7E4CE1:4F + cheat + description:Infinite money (alt) + code:7E0A57:E7+7E0A58:03 + cheat + description:Start with max hit level + code:7E4DA0:30 + +cartridge sha256:0c169bbb4e6dcb3b23e7b3b05e3bddd590f45cecd803a4e5a7118fd606158b23 + title:U.F.O. Kamen Yakisoban - Kettler no Kuroi Inbou (Japan) + cheat + description:Infinite health + code:7E0175:28 + cheat + description:Infinite lives + code:7E0176:07 + cheat + description:Infinite time + code:7E0AF3:B0 + +cartridge sha256:0b155a54b6134601fc0791252a63ca73efd522667c3d6fd7a44f5b3c500039d7 + title:U.N. Squadron (USA) + cheat + description:Invincibility + code:DD37-D76F+6D34-07FF + cheat + description:Infinite lives + code:A923-DDDF+A923-DD6F + cheat + description:Infinite continues + code:AD2C-0D0F + cheat + description:Infinite shots for all weapons + code:2238-A72F + cheat + description:Infinite money + code:A98E-07D4 + cheat + description:Hit anywhere + code:1830-A79F+3435-A4AD+343F-ADDD+4D35-A7DD+4D3F-AD0D + cheat + description:Shoot without stopping + code:C931-07BF + cheat + description:Max power on first pellet pick-up + code:DDE5-A794 + cheat + description:Start with no money + code:DD80-0DAD + cheat + description:Start with $9,000 + code:BD80-0DAD + cheat + description:Start with 1 life and 1 continue + code:DF89-040D + cheat + description:Start with 5 lives and 5 continues + code:D989-040D + cheat + description:Start with 9 lives and 9 continues + code:DB89-040D + cheat + description:Invincibility (alt) + code:7E00F7:01 + cheat + description:Infinite health + code:7E1008:08 + cheat + description:Infinite shots for all weapons (alt) + code:04E7BF:DD + cheat + description:Infinite money (alt) + code:00B9FC:C5 + cheat + description:Infinite lives (alt) + code:00D4E0:C5+00D4E2:C5 + cheat + description:Infinite continues (alt) + code:7E00F3:03 + cheat + description:Enable all 6 jets selectable for free + code:7E00F6:3F + cheat + description:Loads of money - P1 + code:7E00D9:01 + cheat + description:Infinite Conventional Bombs + code:7E00DD:31 + cheat + description:Infinite Mega Crush Weapons + code:7E00DD:02 + cheat + description:Infinite Thunder Laser + code:7E00DD:14 + +cartridge sha256:094555d5720158ee60c9d5ab9a13110192db5ebf0f6cf69abbb59a00bc470345 + title:Ultima - Runes of Virtue II (USA) + cheat + description:Infinite energy - makes enemies invincible too (Shamino in easy mode) + code:C2C3-47A7 + cheat + description:Stars never recharge (Shamino in easy mode) + code:CB3B-1464 + cheat + description:Almost infinite stars (Shamino in easy mode) + code:CB67-3764 + cheat + description:Start with a stronger armor (Shamino in easy mode) + code:CB6C-4D68+4A6C-4DA8 + cheat + description:Start with less stars (Shamino in easy mode) + code:DF69-4FD8 + cheat + description:Start with Crossbow instead of the Axe (Shamino in easy mode) + code:7760-47D8 + cheat + description:Start with Longbow instead of the Axe (Shamino in easy mode) + code:7060-47D8 + cheat + description:Start with Fireball wand instead of the Axe (Shamino in easy mode) + code:7560-47D8 + cheat + description:Start with Boomerang instead of the Axe (Shamino in easy mode) + code:7660-47D8 + cheat + description:Start with Shuriken instead of the Axe (Shamino in easy mode) + code:4E60-47D8 + cheat + description:Start with 30 intelligence (Shamino in easy mode) + code:7D60-4768 + cheat + description:Start with 5 intelligence (Shamino in easy mode) + code:D960-4768 + +cartridge sha256:11659bd8dd620d50400d16042aeb2d0ddb00c7183fc1ecb95b1a34f07db0431b + title:Ultima VI - The False Prophet (USA) + cheat + description:Infinite time + code:89C8-D76D + cheat + description:Infinite Gold + code:7E014B:FF+7E014C:FF + cheat + description:Max Karma + code:7E014A:64 + cheat + description:Infinite Energy (Avatar) + code:7E8603:F0 + cheat + description:Infinite Energy (Shamino) + code:7E8607:F0 + cheat + description:Infinite Energy (Iolo) + code:7E8609:F0 + cheat + description:Infinite Energy (Dupre) + code:7E8605:F0 + cheat + description:Infinite MP (Avatar) + code:7E8C02:3C + cheat + description:Infinite MP (Shamino) + code:7E8C06:3C + cheat + description:Infinite MP (Iolo) + code:7E8C08:3C + cheat + description:Infinite MP (Dupre) + code:7E8C04:3C + cheat + description:Infinite Energy (Jaana) + code:7E867D:F0 + cheat + description:Infinite Energy (Gwenno) + code:7E8685:F0 + cheat + description:Infinite Energy (Seggal) + code:7E8741:F0 + cheat + description:Infinite Energy (Katrina) + code:7E86C3:F0 + cheat + description:Infinite Energy (Sentri) + code:7E874D:F0 + cheat + description:Infinite Energy (Leodon) + code:7E86E3:F0 + cheat + description:Infinite Energy (Gorn) + code:7E8757:F0 + cheat + description:Infinite Energy (Leonna) + code:7E86E5:F0 + cheat + description:Infinite Energy (Blaine) + code:7E870F:F0 + cheat + description:Infinite Energy (Beh Lem) + code:7E875D:F0 + cheat + description:Infinite Energy (Julia) + code:7E8687:F0 + cheat + description:Infinite MP (Gwenno) + code:7E8C84:3C + cheat + description:Infinite MP (Jaana) + code:7E8C7C:3C + cheat + description:Infinite MP (Julia) + code:7E8C86:3C + cheat + description:Infinite MP (Katrina) + code:7E8CC2:3C + cheat + description:Infinite MP (Seggal) + code:7E8D40:3C + cheat + description:Infinite MP (Sentri) + code:7E8D4C:3C + cheat + description:Infinite MP (Gorn) + code:7E8D56:3C + cheat + description:Infinite MP (Leodon) + code:7E8CE2:3C + cheat + description:Infinite MP (Leonna) + code:7E8CE4:3C + cheat + description:Infinite MP (Blaine) + code:7E8D0E:3C + cheat + description:Infinite MP (Beh Lem) + code:7E8D5C:3C + cheat + description:Max Experience (Gwenno) + code:7E8884:0F+7E8885:27 + cheat + description:Max Experience (Seggal) + code:7E8940:0F+7E8941:27 + cheat + description:Max Experience (Sentri) + code:7E894C:0F+7E894D:27 + cheat + description:Max Experience (Julia) + code:7E8886:0F+7E8887:27 + cheat + description:Max Experience (Katrina) + code:7E88C2:0F+7E88C3:27 + cheat + description:Max Experience (Jaana) + code:7E887C:0F+7E887D:27 + cheat + description:Max Experience (Blaine) + code:7E890E:0F+7E890F:27 + cheat + description:Max Experience (Beh Lem) + code:7E895C:0F+7E895D:27 + cheat + description:Max Experience (Gorn) + code:7E8956:0F+7E8957:27 + cheat + description:Max Experience (Leonna) + code:7E88E4:0F+7E88E5:27 + cheat + description:Max Experience (Leodon) + code:7E88E2:0F+7E88E3:27 + cheat + description:Max Experience (Avatar) + code:7E8802:0F+7E8803:27 + cheat + description:Max Experience (Dupre) + code:7E8804:0F+7E8805:27 + cheat + description:Max Experience (Shamino) + code:7E8806:0F+7E8807:27 + cheat + description:Max Experience (Iolo) + code:7E8808:0F+7E8809:27 + +cartridge sha256:a31af0e39afb55bbc92a5543b504327fbe7e8cd0a5e08626976bed7b65376737 + title:Ultima VII - The Black Gate (USA) + cheat + description:Infinite health + code:7E1CFA:E4 + cheat + description:Infinite Keys + code:7E1CFC:63 + cheat + description:65,000 Exp + code:7E1D00:E8+7E1D01:FD + cheat + description:65,000 Gold + code:7E1CE6:E8+7E1CE7:FD + +cartridge sha256:78bf82963cded9162e25035053c8b1a9f760748ff0beacc230d005204992737d + title:Ultimate Fighter (USA) + cheat + description:Infinite health + code:7E1402:C8 + cheat + description:Infinite lives - story mode + code:7E09C9:63 + cheat + description:Start with 60,000 score + code:7E09B9:60+7E09BA:EA + +cartridge sha256:cb2fdfce61858063bf4c9da4228381c3ec3abe423f4d378cddd174ae4adb261e + title:Ultimate Mortal Kombat 3 (USA) + cheat + description:Invincibility (throws damage CPU) + code:3D3C-C79F+6D33-3DBF+7D38-CDFF+DF3C-C7BF+E138-CD9F + cheat + description:Infinite health - P1 + code:C172-B27B + cheat + description:Infinite health - P2 + code:C17B-F37C + cheat + description:Infinite run - P1 + code:7D72-B37B + cheat + description:Infinite run - P2 + code:7D7B-FE7C + cheat + description:Max fatality time + code:DF73-2A7C + cheat + description:Hit anywhere - P1 + code:46EB-3FB7+84EB-3497+BD3C-C49F+D4EB-3D97+DDEB-3DB7+D7EB-3FF7+EDEB-3D27+EE3C-C4BF+0AEB-3F97+0AEB-34F7+31EB-34B7+35EB-3F27+3DEB-3DF7 + cheat + description:Blank versus screen + code:EE37-CF02 + cheat + description:Scrambled backgrounds + code:C2B1-1FBF + cheat + description:Black background (wait for title screen to appear before proceeding) + code:C2B6-1FFF + cheat + description:First round / one button fatalities + code:7E3BE3:01 + +cartridge sha256:e9fae4c2e171a1fc4f2bd800abd9e42750aaf7a4db9e40c5b9142e15029500bd + title:Ultraman - Towards the Future (USA) + cheat + description:Infinite health + code:4ABA-67DF + cheat + description:Infinite health - P1 + code:7E07EE:53 + cheat + description:No health - P2 + code:7E084E:00 + cheat + description:Infinite chances + code:4024-6FA7 + cheat + description:Infinite time (seconds) + code:7E00A3:63 + cheat + description:Infinite time (minutes) + code:7E00A4:09 + cheat + description:Quicker health replenishment + code:DD8F-DF0D + cheat + description:Less health replenishment for enemies + code:3C80-DDDD + cheat + description:Weaker punch + code:DFAC-D76E + cheat + description:Weaker kick + code:DFA8-DDDE + cheat + description:9 minutes per stage + code:DBB4-DD6D + cheat + description:6 minutes per stage + code:D1B4-DD6D + cheat + description:2 minutes per stage + code:D4B4-DD6D + cheat + description:Start with 1 chance + code:DD6C-0467 + cheat + description:Start with 6 chances + code:D96C-0467 + cheat + description:Start with 9 chances + code:DB6C-0467 + cheat + description:Start on stage 1 - Gudis + code:7E00F8:00 + cheat + description:Start on stage 2 - Bogun + code:7E00F8:01 + cheat + description:Start on stage 3 - Degola + code:7E00F8:02 + cheat + description:Start on stage 4 - Barrangas + code:7E00F8:03 + cheat + description:Start on stage 5 - Gudis II + code:7E00F8:04 + cheat + description:Start on stage 6 - Zebokon + code:7E00F8:05 + cheat + description:Start on stage 7 - Majaba + code:7E00F8:06 + cheat + description:Start on stage 8 - Kodalar + code:7E00F8:07 + cheat + description:Start on final stage - Kilazee + code:7E00F8:08 + +cartridge sha256:794152fc6f55cb15a0b203fa645ac9fa314a293da999d8ec8b3dda080434d175 + title:Uncharted Waters (USA) + cheat + description:Start with 65,000 Gold + code:E2EF-D7D5 + +cartridge sha256:64bc4707f422661a66618088887e2363a5f896ea683c58984fffd96dd21ab5f0 + title:Uncharted Waters - New Horizons (USA) + cheat + description:Joao starts with 156 Leadership instead of 78 + code:BA6D-873D + cheat + description:Joao starts with 250 Leadership instead of 78 + code:EC6D-873D + cheat + description:Joao starts with 150 Seamanship instead of 75 + code:B16F-8D4D + cheat + description:Joao starts with 250 Seamanship instead of 75 + code:EC6F-8D4D + cheat + description:Joao starts with 146 Knowledge instead of 73 + code:B46F-8D1D + cheat + description:Joao starts with 250 Knowledge instead of 73 + code:EC6F-8D1D + cheat + description:Joao starts with 170 Intuition instead of 85 + code:CC6F-8DCD + cheat + description:Joao starts with 250 Intuition instead of 85 + code:EC6F-8DCD + cheat + description:Joao starts with 164 Courage instead of 82 + code:C06F-8D3D + cheat + description:Joao starts with 250 Courage instead of 82 + code:EC6F-8D3D + cheat + description:Joao starts with 164 Dueling Skill instead of 82 + code:C06F-8F4D + cheat + description:Joao starts with 250 Dueling Skill instead of 82 + code:EC6F-8F4D + cheat + description:Joao starts with 178 Likability (Charm) instead of 89 + code:846F-8F1D + cheat + description:Joao starts with 250 Likability (Charm) instead of 89 + code:EC6F-8F1D + cheat + description:Catalina starts with 24 Sail Level instead of 8 + code:F660-841D + cheat + description:Catalina starts with 80 Sail Level instead of 8 + code:9D60-841D + cheat + description:Catalina starts with 30 Battle Level instead of 10 + code:F360-84CD + cheat + description:Catalina starts with 100 Battle Level instead of 10 + code:1060-84CD + cheat + description:Catalina starts with 160 Leadership instead of 80 + code:CD60-8D1D + cheat + description:Catalina starts with 250 Leadership instead of 80 + code:EC60-8D1D + cheat + description:Catalina starts with 158 Seamanship instead of 79 + code:B360-8DCD + cheat + description:Catalina starts with 250 Seamanship instead of 79 + code:EC60-8DCD + cheat + description:Catalina starts with 130 Knowledge instead of 65 + code:6460-8D3D + cheat + description:Catalina starts with 250 Knowledge instead of 65 + code:EC60-8D3D + cheat + description:Catalina starts with 104 Intuition instead of 52 + code:1660-8F4D + cheat + description:Catalina starts with 250 Intuition instead of 52 + code:EC60-8F4D + cheat + description:Catalina starts with 172 Courage instead of 86 + code:CA60-8F1D + cheat + description:Catalina starts with 250 Courage instead of 86 + code:EC60-8F1D + cheat + description:Catalina starts with 184 Dueling Skill instead of 92 + code:8660-8FCD + cheat + description:Catalina starts with 250 Dueling Skill instead of 92 + code:EC60-8FCD + cheat + description:Catalina starts with 190 Likability instead of 95 + code:8360-8F3D + cheat + description:Catalina starts with 250 Likability instead of 95 + code:EC60-8F3D + cheat + description:Ali Vezas starts with 160 Leadership (instead of 80) + code:CD6D-E41D + cheat + description:Ali Vezas starts with 250 Leadership (instead of 80) + code:EC6D-E41D + cheat + description:Ali Vezas starts with 172 Seamanship (instead of 86) + code:CA6D-E4CD + cheat + description:Ali Vezas starts with 250 Seamanship (instead of 86) + code:EC6D-E4CD + cheat + description:Ali Vezas starts with 168 Knowledge (instead of 84) + code:C66D-E43D + cheat + description:Ali Vezas starts with 250 Knowledge (instead of 84) + code:EC6D-E43D + cheat + description:Ali Vezas starts with 130 Intuition (instead of 65) + code:646D-E74D + cheat + description:Ali Vezas starts with 250 Intuition (instead of 65) + code:EC6D-E74D + cheat + description:Ali Vezas starts with 106 Courage (instead of 53) + code:1C6D-E71D + cheat + description:Ali Vezas starts with 250 Courage (instead of 53) + code:EC6D-E71D + cheat + description:Ali Vezas starts with 84 Dueling Skill (instead of 42) + code:906D-E7CD + cheat + description:Ali Vezas starts with 250 Dueling Skill (instead of 42) + code:EC6D-E7CD + cheat + description:Ali Vezas starts with 160 Likability (instead of 80) + code:CD6D-E73D + cheat + description:Ali Vezas starts with 250 Likability (instead of 80) + code:EC6D-E73D + cheat + description:Start a new game with $250 Gold + code:EC63-543D + cheat + description:Start a new game with $1,024 Gold + code:D063-574D + cheat + description:Start a new game with $9,984 Gold + code:4563-574D + cheat + description:Start a new game with $64,000 Gold + code:EC63-574D + cheat + description:Start a new game with $196,608 Gold + code:D763-571D + cheat + description:Start a new game with over one Million Gold + code:FD63-571D + cheat + description:No Storms + code:7E201B:80 + cheat + description:1 D.a.s., No Scurvy + code:7E415E:00 + cheat + description:Joao's Steering Power + code:7E2620:FF + cheat + description:Joao's Battle Power + code:7E2621:FF + cheat + description:Ali's Steering Power + code:7E271A:FF + cheat + description:Ali's Battle Power + code:7E271B:FF + cheat + description:Pietro's Steering Power + code:7E26E8:FF + cheat + description:Pietro's Battle Power + code:7E26E9:FF + cheat + description:Max Adventure For Joao + code:7E25A4:50+7E25A5:C3 + cheat + description:100% Popular In Portugal + code:7E25A6:C8 + cheat + description:100% Popular In Spain + code:7E25A7:C8 + cheat + description:100% Popular In Turkey + code:7E25A8:C8 + cheat + description:100% Popular In England + code:7E25A9:C8 + cheat + description:100% Popular In Italy + code:7E25AA:C8 + cheat + description:100% Popular In Holland + code:7E25AB:C8 + cheat + description:S.1 Infinite Water + code:7E661A:7F + cheat + description:S.2 Infinite Water + code:7E6638:7F + cheat + description:S.3 Infinite Water + code:7E6656:7F + cheat + description:S.4 Infinite Water + code:7E6674:7F + cheat + description:S.5 Infinite Water + code:7E6692:7F + cheat + description:S.6 Infinite Water + code:7E66B0:7F + cheat + description:S.7 Infinite Water + code:7E66CE:7F + cheat + description:S.8 Infinite Water + code:7E66EC:7F + cheat + description:S.9 Infinite Water + code:7E670A:7F + cheat + description:S.10 Infinite Water + code:7E6728:7F + cheat + description:S.11 Infinite Water + code:7E6746:7F + cheat + description:S.12 Infinite Water + code:7E6764:7F + cheat + description:S.13 Infinite Water + code:7E6782:7F + cheat + description:S.14 Infinite Water + code:7E67A0:7F + cheat + description:S.15 Infinite Water + code:7E67BE:7F + cheat + description:S.16 Infinite Water + code:7E67DC:7F + cheat + description:S.17 Infinite Water + code:7E67FA:7F + cheat + description:S.1 Infinite Food + code:7E661C:7F + cheat + description:S.2 Infinite Food + code:7E663A:7F + cheat + description:S.3 Infinite Food + code:7E6658:7F + cheat + description:S.4 Infinite Food + code:7E6676:7F + cheat + description:S.5 Infinite Food + code:7E6694:7F + cheat + description:S.6 Infinite Food + code:7E66B2:7F + cheat + description:S.7 Infinite Food + code:7E66D0:7F + cheat + description:S.8 Infinite Food + code:7E66EE:7F + cheat + description:S.9 Infinite Food + code:7E670C:7F + cheat + description:S.10 Infinite Food + code:7E672A:7F + cheat + description:S.11 Infinite Food + code:7E6748:7F + cheat + description:S.12 Infinite Food + code:7E6766:7F + cheat + description:S.13 Infinite Food + code:7E6784:7F + cheat + description:S.14 Infinite Food + code:7E67A2:7F + cheat + description:S.15 Infinite Food + code:7E67C0:7F + cheat + description:S.16 Infinite Food + code:7E67D7:7F + cheat + description:S.17 Infinite Food + code:7E67FC:7F + cheat + description:S.1 Infinite Crew (Ship HP) + code:7E41E7:22 + cheat + description:S.2 Infinite Crew (Ship HP) + code:7E41F0:22 + cheat + description:S.3 Infinite Crew (Ship HP) + code:7E41F9:22 + cheat + description:S.4 Infinite Crew (Ship HP) + code:7E4202:22 + cheat + description:S.5 Infinite Crew (Ship HP) + code:7E420B:22 + cheat + description:S.6 Infinite Crew (Ship HP) + code:7E4214:22 + cheat + description:S.7 Infinite Crew (Ship HP) + code:7E421D:22 + cheat + description:S.8 Infinite Crew (Ship HP) + code:7E4226:22 + cheat + description:S.9 Infinite Crew (Ship HP) + code:7E422F:22 + cheat + description:S.10 Infinite Crew (Ship HP) + code:7E4238:22 + cheat + description:S.11 Infinite Crew (Ship HP) + code:7E4241:22 + cheat + description:S.12 Infinite Crew (Ship HP) + code:7E424A:22 + cheat + description:S.13 Infinite Crew (Ship HP) + code:7E4253:22 + cheat + description:S.14 Infinite Crew (Ship HP) + code:7E425C:22 + cheat + description:S.15 Infinite Crew (Ship HP) + code:7E4265:22 + cheat + description:S.16 Infinite Crew (Ship HP) + code:7E426E:22 + cheat + description:S.17 Infinite Crew (Ship HP) + code:7E4277:22 + cheat + description:S.1 Speedy + code:7E41EB:FF + cheat + description:S.2 Speedy + code:7E41F4:FF + cheat + description:S.3 Speedy + code:7E41FD:FF + cheat + description:S.4 Speedy + code:7E4206:FF + cheat + description:S.5 Speedy + code:7E420F:FF + cheat + description:S.6 Speedy + code:7E4218:FF + cheat + description:S.7 Speedy + code:7E4221:FF + cheat + description:S.8 Speedy + code:7E422A:FF + cheat + description:S.9 Speedy + code:7E4233:FF + cheat + description:S.10 Speedy + code:7E423C:FF + cheat + description:S.11 Speedy + code:7E4245:FF + cheat + description:S.12 Speedy + code:7E424E:FF + cheat + description:S.13 Speedy + code:7E4257:FF + cheat + description:S.14 Speedy + code:7E4260:FF + cheat + description:S.15 Speedy + code:7E4269:FF + +cartridge sha256:cb8073cf95eace56ba4324a2106164fa540900c2de083aff490c4afe91ae95f7 + title:Undercover Cops (Japan) + cheat + description:Infinite health + code:C266-57D7 + cheat + description:Infinite lives + code:C2E3-77A7 + cheat + description:Infinite time + code:C2D4-8F61 + cheat + description:Infinite continues + code:C203-E4A1 + cheat + description:Hit anywhere + code:6D2E-770F+732E-776F + cheat + description:one hit kils + code:DD20-546F + cheat + description:Infinite health (alt) + code:7E0C36:E8+7E0D36:E8 + cheat + description:Infinite lives (alt) + code:7E0110:0A + cheat + description:Infinite time (alt) + code:7E016C:64 + cheat + description:Infinite continues (alt) + code:7E0112:09 + +cartridge sha256:859ec99fdc25dd9b239d9085bf656e4f49c93a32faa5bb248da83efd68ebd478 + title:Uniracers (USA) + cheat + description:No timer in almost every race + code:3CA4-3F69 + cheat + description:No timer in almost every race (alt) + code:81C726:EA + +cartridge sha256:cf587d72123277f72f658829f1efdb4f52f3bec012a316c1fea25e1f9c292575 + title:Universal Soldier (USA) (Proto) + cheat + description:Infinite health + code:C2E3-0F6F + cheat + description:Infinite lines + code:C26D-0F09 + +cartridge sha256:ecefb4117a6aae117e033c8cc07f0db2797d6be93dd5cdcefc23692a21fae02e + title:Untouchables, The (USA) + cheat + description:Infinite lives + code:7E1B86:09 + cheat + description:Infinite ammo + code:7E1B89:63 + +cartridge sha256:8b3ff3a0ca1c85facb71f42886291dfa916ca74245702c79ca8ae635f28bc864 + title:Ushio to Tora (Japan) + cheat + description:Invincibility + code:7E0222:26 + cheat + description:Infinite health + code:7E021E:40 + cheat + description:Infinite lives + code:7E0608:63 + +cartridge sha256:2500d6c846c78bcb729f15535bf2b852a120411891cabaaaa6fc407906d0214e + title:Utopia - The Creation of a Nation (USA) + cheat + description:1-day buildings + code:DDBB-6D0F + cheat + description:Have 655360000 cash (enable while on map then disable) + code:CBC3-040F+69C3-07DF+5FC3-070F + +cartridge sha256:78bf9d79fb2ff3f9d03ecc1176d070e53ddaca2c6b0cda69e74c19a4e50b195b + title:Vegas Stakes (USA) + cheat + description:Only $34,464 needed for highroller status (glitchy) + code:DDA0-A4AD + cheat + description:Only $38,527 needed to win the game instead of $10 million + code:DDA8-640D + cheat + description:Only $5,019,263 needed to win the game + code:0AA8-640D + cheat + description:Player wins pushes in Blackjack + code:DD87-04EC + cheat + description:Dealer wins pushes in Blackjack + code:DF87-04EC + cheat + description:Start with $488 - P1 + code:DF81-A4D7 + cheat + description:Start with $488 - P2 + code:DF8B-AF07 + cheat + description:Start with $488 - P3 + code:DF8A-AD67 + cheat + description:Start with $488 - P4 + code:DF83-A7A7 + cheat + description:Start with $2280 - P1 + code:D681-A4D7 + cheat + description:Start with $2280 - P2 + code:D68B-AF07 + cheat + description:Start with $2280 - P3 + code:D68A-AD67 + cheat + description:Start with $2280 - P4 + code:D683-A7A7 + cheat + description:Start with $9960 - P1 + code:4181-A4D7 + cheat + description:Start with $9960 - P2 + code:418B-AF07 + cheat + description:Start with $9960 - P3 + code:418A-AD67 + cheat + description:Start with $9960 - P4 + code:4183-A7A7 + cheat + description:Start with $132,072 (highroller status) - P1 + code:D481-A707 + cheat + description:Start with $132,072 - P2 + code:D48B-A467 + cheat + description:Start with $132,072 - P3 + code:D48A-AFA7 + cheat + description:Start with $132,072 - P4 + code:D48E-AFD7 + +cartridge sha256:b72fbbfe737eff49f59dcef9f13b963e50c5bc322d7eb0e7b4c25f3a71aa0815 + title:Venom-Spider-Man - Separation Anxiety (USA) + cheat + description:Infinite health - P1 + code:8935-1FD6 + cheat + description:Infinite lives - P1 + code:5BC9-1FD9 + cheat + description:Infinite health - P2 + code:7E0A5A:99 + cheat + description:Infinite lives - P2 + code:7E1A8B:06 + cheat + description:Stage select enabled + code:7E1C40:FF + cheat + description:Hard mode enabled + code:7E1C3C:FF + cheat + description:Use helpers multiple times + code:7E1BC4:00 + cheat + description:Infinite Captain America hero icons + code:7E1BC5:05 + cheat + description:Infinite Ghost Rider hero icons + code:7E1BC7:05 + cheat + description:Infinite Daredevil hero icons + code:7E1BC9:05 + cheat + description:Infinite Hawkeye hero icons + code:7E1BCB:05 + cheat + description:Infinite Vault Guardsman hero icon + code:7E1BCD:05 + cheat + description:One hit kills for most enemies and some bosses + code:7E0AD3:00+7E0B4C:00+7E0BC5:00+7E0C3E:00+7E0CB7:00 + +cartridge sha256:29c28188234ddbb0b72fc84253dcd3514e23034779c773db8097b073b73390c8 + title:Virtual Bart (USA) + cheat + description:Infinite time + code:C239-37AF + cheat + description:Infinite health and Tomatoes (Baby Bart takes damage when he walks on grass) + code:053E-44A4 + cheat + description:Infinite continues + code:C238-44A4 + cheat + description:Infinite lives + code:C23C-4704 + +cartridge sha256:41b5561de9e4984276e52987ea46c5f4fa8526d8141c70c738875a9eb9fe9d70 + title:Vortex (USA) (En,Es) + cheat + description:Infinite health + code:7E039A:3D+7E118B:32 + cheat + description:Infinite lives + code:7E120E:0A + cheat + description:Infinite Missiles + code:7E1DE4:63 + cheat + description:Infinite Rockets + code:7E1DE5:63 + cheat + description:Infinite Cannon + code:7E1DE6:63 + cheat + description:Infinite Blasts + code:7E121A:63 + +cartridge sha256:8579dd352d20589072ed5c026bde7adadd6229d18a022e7cb47cf5602b54015e + title:Warlock (USA) + cheat + description:Invincibility + code:CBBE-A4D7+33CC-DD64 + cheat + description:Infinite items on pick-up + code:3C65-D46C + cheat + description:Enter the password GRKKL to go to the final battle + code:7FAC-DD2F + cheat + description:Enter the password GRKKL to go to the ending + code:74AC-DD2F + +cartridge sha256:56ba3d585bf6b701e342d86a0bd164ab0a97dfbd5df46b3a964506842633459c + title:Wayne's World (USA) + cheat + description:Infinite Worthiness + code:C2BC-D728 + cheat + description:Infinite lives + code:C28F-0704 + cheat + description:Worthiness item worth nothing on pick-up + code:C2B5-04BC + cheat + description:Schwing item worth nothing on pick-up + code:C2B0-04BC + cheat + description:Infinite Schwings if you have at least 1 + code:C269-0DBB + cheat + description:Invincibility lasts longer after getting hit + code:EEB3-DF98 + cheat + description:Invincibility does not last as long after getting hit + code:FDB3-DF98 + cheat + description:Invincibility lasts forever after getting hit (Wayne blinks) + code:82BB-0FF8 + cheat + description:Invincibility (Wayne doesn't blink) + code:6DBB-D428 + cheat + description:Amp power-up worth nothing on pick-up + code:DDBB-D4BC + cheat + description:Amp power-up gives you Distortion-type chords + code:D0BB-D4BC + cheat + description:Amp power-up gives you Mega-Amp-type chords + code:D4BB-D4BC + cheat + description:Amp power-up gives you Chorus-type chords + code:D7BB-D4BC + cheat + description:Amp power-up gives you Homer-type chords + code:D9BB-D4BC + cheat + description:Distortion power-up worth nothing on pick-up + code:DDBD-0DFC + cheat + description:Distortion power-up gives you Amp-type chords + code:DFBD-0DFC + cheat + description:Distortion power-up gives you Mega-Amp-type chords + code:D4BD-0DFC + cheat + description:Distortion power-up gives you Chorus-type-chords + code:D7BD-0DFC + cheat + description:Distortion power-up gives you Homer-type-chords + code:D9BD-0DFC + cheat + description:Heart item worth nothing + code:C2BB-079C + cheat + description:Start with 1 life + code:DFAA-A764 + cheat + description:Start with 3 lives + code:D7AA-A764 + cheat + description:Start with 7 lives + code:D5AA-A764 + cheat + description:Start with 9 lives + code:DBAA-A764 + cheat + description:Start with 1 Worthiness point + code:DF87-0764 + cheat + description:Start with 3 Worthiness points + code:D787-0764 + cheat + description:Start with 7 Worthiness points + code:D587-0764 + cheat + description:Start with 9 Worthiness points + code:DB87-0764 + +cartridge sha256:0b1ba31ae95b61d7d9a0f5509b5836fff84f60915802e3b3ba1170a5c50a4b71 + title:WeaponLord (USA) + cheat + description:Play as Zarak in story mode + code:D13C-561B + cheat + description:Infinite health - P1 + code:5C1A-7B3B + cheat + description:Infinite health - both players + code:C21A-7BCB + cheat + description:Infinite time + code:C204-56C5 + +cartridge sha256:e931c3c08f20f78e3a43ad92d16eb472be619abaa17c2d8e2b0fcd5d05dbd74d + title:We're Back! - A Dinosaur's Story (USA) + cheat + description:Infinite health + code:C2B2-C54B + cheat + description:Infinite lives + code:C265-41CB + cheat + description:Infinite Vorb on pick-up for the rest of the stage + code:C2C6-C148 + cheat + description:Infinite Elsa on pick-up for the rest of the stage + code:C2C1-301B + cheat + description:Infinite Dweebs on pick-up for the rest of the stage + code:C2C5-4038 + cheat + description:Infinite Woog on pick-up + code:C2C1-194C + cheat + description:Super-jump + code:FEB1-C14C + cheat + description:Mega-jump + code:4EB1-C14C + cheat + description:Less grain to get for tail swipe + code:D76D-111C + cheat + description:Less grain to get for stomp + code:DB6D-103C + cheat + description:Start with less health + code:D48B-C110+D466-49CC + cheat + description:Start with 9 lives + code:DB8B-C030 + cheat + description:Start with 6 lives + code:D18B-C030 + cheat + description:Start with 1 life + code:DF8B-C030 + cheat + description:Start on Manhattan - Zone 2 + code:CB85-1530+D486-1040+DD86-1010 + cheat + description:Start on the Subway + code:CB85-1530+D786-1040+DD86-1010 + cheat + description:Start on Crazy Crane + code:CB85-1530+D086-1040+DD86-1010 + cheat + description:Start on Construction in the City + code:CB85-1530+D186-1040+DD86-1010 + cheat + description:Start on Thanksgiving - Zone 1 + code:CB85-1530+D586-1040+DD86-1010 + cheat + description:Start on Thanksgiving - Zone 2 + code:CB85-1530+D686-1040+DD86-1010 + cheat + description:Start on Balloon Blow-out + code:CB85-1530+DB86-1040+DD86-1010 + cheat + description:Start on Central Park - Zone 1 + code:CB85-1530+D886-1040+DD86-1010 + cheat + description:Start on Central Park - Zone 2 + code:CB85-1530+DA86-1040+DD86-1010 + cheat + description:Start on the Zoo + code:CB85-1530+D286-1040+DD86-1010 + cheat + description:Start on Prehistoric Panic + code:CB85-1530+D386-1040+DD86-1010 + cheat + description:Start on Outside the Circus + code:CB85-1530+FD86-1040+DD86-1010 + cheat + description:Start on Circus - Zone 1 + code:CB85-1530+FF86-1040+DD86-1010 + cheat + description:Start on Circus - Zone 2 + code:CB85-1530+F486-1040+DD86-1010 + cheat + description:Start on Jack in the Box + code:CB85-1530+F786-1040+DD86-1010 + cheat + description:Start on Empire State Building + code:CB85-1530+F986-1040+DD86-1010 + cheat + description:Start on Spaceship - Zone 1 + code:CB85-1530+F186-1040+DD86-1010 + cheat + description:Start on Spaceship - Zone 2 + code:CB85-1530+F586-1040+DD86-1010 + cheat + description:Infinite health (alt) + code:9A96DC:AD + cheat + description:Infinite lives (alt) + code:9A847A:AD + cheat + description:Super-jump (alt) + code:9A9A68:1F + cheat + description:Mega-jump (alt) + code:9A9A68:2F + +cartridge sha256:12abf1ba063c120c1a98495a1c85e67a0007aff771ef92adcb94b4a0a2fd5adb + title:Wheel of Fortune (USA) + cheat + description:Infinite time to choose + code:C264-DF0F + cheat + description:Don't lose money when landing on bankrupt + code:C2BE-DFDF + cheat + description:3/4 of normal time to choose + code:F3B1-DF64 + cheat + description:1/2 of normal time to choose + code:F0B1-DF64 + cheat + description:1/4 of normal time to choose + code:DCB1-DF64 + cheat + description:Vowels are free is you have at least $250 + code:DD62-DF07 + cheat + description:Vowels cost $50 if you have at least $250 + code:7462-DF07 + cheat + description:Vowels cost $100 if you have at least $250 + code:1062-DF07 + cheat + description:Vowels cost $150 if you have at least $250 + code:B162-DF07 + cheat + description:Vowels cost $200 if you have at least $250 + code:A662-DF07 + +cartridge sha256:0a52dc1e7820f5541f53ce0e1e96144fe079af0efe3dae5c2c89d86365feb8b1 + title:Whizz (USA) + cheat + description:Infinite health + code:C9CC-1FDD + cheat + description:Infinite time + code:C260-37AF + cheat + description:Infinite lives + code:C2C5-37D4 + cheat + description:Infinite time (alt) + code:7E03A4:63 + +cartridge sha256:c8f159e2625ac8078535c06857ea28475706da45df494de8e46f50888272cf71 + title:Wild Guns (USA) + cheat + description:Infinite specials + code:7E1FA0:05 + cheat + description:Infinite lives + code:7E1FB2:04 + +cartridge sha256:2167fc7c5447b2287668d2f3e4ef1a285361b2292ecc8a4cbd9f966a460ad7a2 + title:Wing Commander (USA) + cheat + description:Increase front shield on Hornet + code:7ABC-3713 + cheat + description:Increase rear shield on Hornet + code:7AB4-4D1E + cheat + description:Increase front armor on Hornet + code:0DBB-4F1E + cheat + description:Increase rear armor on Hornet + code:0DBD-141E + cheat + description:Increase left side armor on Hornet + code:0DBE-1D1E + cheat + description:Increase right side armor on Hornet + code:0DB5-171E + cheat + description:Increase front shield on Scimitar + code:17B8-3D13 + cheat + description:Increase rear shield on Scimitar + code:17B4-4F1E + cheat + description:Increase front armor on Scimitar + code:17BB-441E + cheat + description:Increase rear armor on Scimitar + code:17BD-171E + cheat + description:Increase left side armor on Scimitar + code:17BE-1F1E + cheat + description:Increase right side armor on Scimitar + code:17B6-1D1E + cheat + description:Mega front shields on Hornet + code:EEBC-37C3 + cheat + description:Mega rear shields on Hornet + code:EEB4-4DCE + cheat + description:Mega front shields on Scimitar + code:99B8-3DC3 + cheat + description:Mega rear shields on Scimitar + code:99B4-4FCE + +cartridge sha256:132ca0b6a4888edf7de785d48f4417fac28522646e6c7514f80c5e9ff1438d5f + title:Wing Commander - The Secret Missions (USA) + cheat + description:Infinite blaster power + code:C2A6-4D0D + cheat + description:Infinite fuel + code:C2C8-14AD + cheat + description:Infinite missiles + code:3C66-C7A1 + cheat + description:Start on mission 4 + code:D068-C402 + cheat + description:Start on mission 8 + code:D668-C402 + +cartridge sha256:c3bcd5c716f96e6359ebcfd85c3e9b07b46c5124bf4010d89ceef5b6f2f868f6 + title:Wings 2 - Aces High (USA) + cheat + description:Infinite lives - all pilots (you can still get fired) + code:828A-040B + cheat + description:Infinite power-ups + code:C2C6-DDD8 + +cartridge sha256:025dd3047c474d879e69b91a3918add9cdabedf4182e1c1e10e5f0c13a124bf9 + title:Wizard of Oz, The (USA) + cheat + description:Invincibility + code:2D8D-07A5 + cheat + description:Infinite health + code:823C-AD66 + cheat + description:Infinite lives + code:223E-DDAF + cheat + description:Infinite health - Dorthy + code:7E01E5:00 + cheat + description:Infinite health - Scarecrow + code:7E01E7:00 + cheat + description:Infinite health - Tinman + code:7E01E9:00 + cheat + description:Infinite health - Lion + code:7E01EB:00 + cheat + description:Infinite Star Shot - Dorthy + code:7E01DB:09 + cheat + description:Infinite Throwing Rocks - all + code:7E01D1:09 + cheat + description:Have Flight Shoes + code:7E01D3:01 + +cartridge sha256:621180a73a5552899ff2a437e84f2891ec078e9883f25f6671b620ab4db24270 + title:Wizardry VI - Kindan no Mahitsu (Japan) + cheat + description:The whole party doesn't take damage from normal enemy attacks (doesn't protect from poison or certain magic spells) + code:8288-A491 + cheat + description:Create a character and he has a lot of gold + code:4DBF-DD27 + +cartridge sha256:e0165bafeb8d65be08a5a4079f8651104471f450c60794b761b1255853ca2d98 + title:Wolfchild (USA) + cheat + description:Infinite health + code:3CA3-DFAF + cheat + description:Infinite continues + code:C2EC-6FAD + cheat + description:Infinite lives + code:C9A6-A4AD + cheat + description:Infinite Bombs + code:C9A3-DD0F + cheat + description:Stay in wolf form until next continue + code:C2AE-A4DD+C2AE-A4AD + cheat + description:Start with 254 lives and 255 Bombs + code:E366-D7A4 + cheat + description:Start at final boss + code:D866-DFA4 + +cartridge sha256:9c2b458e8fda5cb437a4c6d28fb430e45c4cfef98420c40546b8e08563a4fc7d + title:Wolfenstein 3D (USA) + cheat + description:Infinite health + code:C2CC-5D64 + cheat + description:Infinite ammo + code:C28D-7D0F + cheat + description:Infinite lives + code:C228-E7D4 + cheat + description:Infinite ammo for special weapon 1 after first life + code:C289-77DF + cheat + description:Infinite ammo for special weapon 2 after first life + code:C28F-84DF + cheat + description:Start with 1 life + code:DF25-84D4 + cheat + description:Start with 6 lives + code:D125-84D4 + cheat + description:Start with 9 lives + code:DB25-84D4 + cheat + description:Start with more ammo + code:1729-8704+1728-74D4 + cheat + description:Start with chain gun + code:622C-7764 + cheat + description:Start with machine gun + code:622C-74A4 + cheat + description:Start with special weapon 1 (super machine gun) and ammo after first life + code:622A-7DD4+D02C-7DA4 + cheat + description:Start with special weapon 2 (rocket launcher) and ammo after first life + code:6228-7704+D92C-7DAF + +cartridge sha256:44428a3d1c796fbd41da7620e321c45f11cd80a0e5f4ab8c48177106cb960d77 + title:Wolverine - Adamantium Rage (USA) + cheat + description:Infinite health + code:C9ED-3FAF + cheat + description:Infinite time + code:2DA8-3AA5 + cheat + description:No enemies + code:69E9-3A1F + cheat + description:Invincibility + code:7E00B8:FF + cheat + description:Infinite health (alt) + code:7E1027:64 + +cartridge sha256:ea76cfdbb2a555a7b6eff8b466a879f9a9189639416e8c2fb45bf074e695105f + title:World Heroes (USA) + cheat + description:Infinite health - P1 + code:4008-8FAF + cheat + description:Hit anywhere - P1 + code:7DFE-776D+ADFE-746D+DDFE-74AD+FDFE-77DD + cheat + description:Always win - P1 + code:7B86-84A4 + cheat + description:Win a draw - P1 + code:D409-8F04 + cheat + description:Win a draw - P2 + code:D509-8F04 + cheat + description:Slow timer down by half + code:CD07-84AF + cheat + description:3 hits to win round - either player + code:FB0C-7D64+DD0B-77A4 + cheat + description:2 hits to win round - either player + code:7F0C-7D64+DD0B-77A4 + cheat + description:1 hit to win (sudden death) - either player + code:1F0C-7D64+DD0B-77A4 + cheat + description:Start with more health - P1 + code:5349-87D4 + cheat + description:Start with 1/2 health - P1 + code:7D49-87D4 + cheat + description:Start with very little health - P1 + code:DF49-87D4 + cheat + description:Start with more health - P2/CPU + code:534A-8F64 + cheat + description:Start with half health - P2/CPU + code:7D4A-8F64 + cheat + description:Start with very little health - P2/CPU + code:DF4A-8F64 + +cartridge sha256:159d5341d13d6801324e8271f7191c0223617c9d30984676319b2df7937c78c0 + title:World Heroes 2 (USA) + cheat + description:Invincibility - P1 + code:1D82-AF6D+1D83-0F64 + cheat + description:Invincibility - P2 + code:1D82-0D0D+1D84-DD04 + cheat + description:Hit anywhere - P1 + code:6D8A-07DD+6D8F-D7D4 + cheat + description:Hit anywhere - P2 + code:6D82-AD0D+6D83-0D04 + cheat + description:Infinite health - P1 + code:7E0574:80 + cheat + description:No health - P2 + code:7E0576:00 + cheat + description:Infinite time + code:7E052C:99 + cheat + description:One win wins the match - P1 + code:7E0570:02 + +cartridge sha256:d4d9f1b41dad7e7a126a9adbe8d86c4b339e120c866156796de1cb0c9a214189 + title:World League Soccer (USA) + cheat + description:Each goal worth 2 - P1 + code:D4AC-ADA3 + cheat + description:Each goal worth 3 - P1 + code:D7AC-ADA3 + cheat + description:Each goal worth 4 - P1 + code:D0AC-ADA3 + cheat + description:Each goal worth 5 - P1 + code:D9AC-ADA3 + cheat + description:Each goal worth 6 - P1 + code:D1AC-ADA3 + cheat + description:Each goal worth 7 - P1 + code:D5AC-ADA3 + cheat + description:Each goal worth 8 - P1 + code:D6AC-ADA3 + cheat + description:Each goal worth 9 - P1 + code:DBAC-ADA3 + cheat + description:Each goal worth 2 - P2 + code:D4AD-D7DE + cheat + description:Each goal worth 3 - P2 + code:D7AD-D7DE + cheat + description:Each goal worth 4 - P2 + code:D0AD-D7DE + cheat + description:Each goal worth 5 - P2 + code:D9AD-D7DE + cheat + description:Each goal worth 6 - P2 + code:D1AD-D7DE + cheat + description:Each goal worth 7 - P2 + code:D5AD-D7DE + cheat + description:Each goal worth 8 - P2 + code:D6AD-D7DE + cheat + description:Each goal worth 9 - P2 + code:DBAD-D7DE + +cartridge sha256:0af7b0d3022acd24a1fb15865a076519f7f56e7a4b33f12b6d851b3a91e5388c + title:WWF Raw (USA) + cheat + description:Start with half health + code:D7ED-1C7D + cheat + description:Nobody gets hurt + code:C231-36E3 + cheat + description:No out of ring timer + code:C2E3-C653 + cheat + description:Infinite health - P1 + code:7E0A78:A0 + cheat + description:Two punch knockouts + code:7E0F44:01 + cheat + description:Max grapple meter - P1 + code:7E0B44:BE+7E0B45:02+7E0B46:00 + +cartridge sha256:51c53e36ed0b959b0695fc6ef036fa7302d1c995eca35c28261d6f3cb77df0ca + title:WWF Royal Rumble (USA) + cheat + description:Max grapple meter - P1 + code:7E06DE:FF+7E06DF:02+7E06E0:00 + cheat + description:Two punch knockouts + code:7E092C:01 + +cartridge sha256:0b9abf2fc25a5f07c71f9d8efbb0d0e616c1494060138fbb63f7398e9c26198e + title:WWF Super WrestleMania (USA) + cheat + description:Punches and kicks (except flying drop kick) do no damage + code:DDB1-DF07 + cheat + description:Punches and kicks (except flying drop kick) do more damage + code:D7B1-DF07 + cheat + description:Punches and kicks (except flying drop kick) do a lot more damage + code:D1B1-DF07 + cheat + description:Stomps do no damage + code:DDB0-0FA7 + cheat + description:Stomps do more damage + code:D7B0-0FA7 + cheat + description:Stomps do a lot more damage + code:D1B0-0FA7 + cheat + description:Elbow drops do no damage + code:DDEE-DF91 + cheat + description:Elbow drops do more damage + code:D9EE-DF91 + cheat + description:Elbow drops do a lot more damage + code:D6EE-DF91 + cheat + description:Flying elbow drops do no damage + code:DDEE-DF21 + cheat + description:Flying elbow drops do more damage + code:D5EE-DF21 + cheat + description:Flying elbow drops do a lot more damage + code:DCEE-DF21 + cheat + description:Headbutts do no damage + code:DDBB-0407 + cheat + description:Headbutts do more damage + code:D1BB-0407 + cheat + description:Headbutts do a lot more damage + code:DBBB-0407 + cheat + description:Start with 1/4 health - both players + code:DAC6-6FDD + cheat + description:Start with 1/2 health - both players + code:F6C6-6FDD + cheat + description:Start with 3/4 health - both players + code:40C6-6FDD + +cartridge sha256:67faa6ed3406a5ab0d7224b811c0960bb36560040ee959bb3304c9293ceaa093 + title:WWF WrestleMania - The Arcade Game (USA) + cheat + description:Infinite time + code:3CF0-7B91 + cheat + description:Do mega damage and don't die + code:C9D2-8FDA + cheat + description:Max combo meter + code:CBF0-84DE+6DF0-84AE + cheat + description:Start with 1/4 health + code:4DD0-7D0A+4DD2-740A + cheat + description:Start with 1/2 health + code:OED0-7D0A+0ED2-740A + cheat + description:Start with 3/4 health + code:56D0-7D0A+56D2-740A + cheat + description:Start with 1/4 health - opponent + code:4DDF-7D6A + cheat + description:Start with 1/2 health - opponent + code:0EDF-7D6A + cheat + description:Start with 3/4 health - opponent + code:56DF-7D6A + +cartridge sha256:71b69490c78d0bbaf47da25217c5dae295190311aa5df75653c3fac0a1b45358 + title:Xardion (USA) + cheat + description:Immune to most collisions + code:4A25-0FB4 + cheat + description:Immune to most bullets + code:4A31-6DFD + cheat + description:Start characters at level 12 + code:DDE2-07CD + +cartridge sha256:dc3792e9fe7ef7aaea4ac675a48ad06129dd3ebdd4b96a513bc8241549cbd579 + title:X-Kaliber 2097 (USA) + cheat + description:Infinite time + code:C260-D767 + cheat + description:Infinite lives + code:3C6C-A76D + cheat + description:Soda Cans give 50% life back + code:9C63-D56D + cheat + description:Infinite health - P1 + code:7E0A18:90 + cheat + description:Infinite lives - P1 + code:7E0A3E:09 + cheat + description:Infinite continues - P1 + code:7E0A46:09 + cheat + description:Infinite time (alt) + code:7E0A21:5A + +cartridge sha256:65fe17fd6b297f52df6ce9812ecb02c3bb1bfda3ebc05a19c4a8decbf9a446ae + title:X-Men - Mutant Apocalypse (USA) + cheat + description:Infinite health + code:33DB-E407 + cheat + description:Infinite health (alt) + code:7E008B:41+7E0C35:41 + cheat + description:Infinite lives - training mode + code:C2D1-8F67 + cheat + description:Infinite lives - mission mode + code:C2D7-5F64 + cheat + description:Easy specials (press X) + code:3344-E701 + cheat + description:Walk through walls + code:C247-84D7+89D2-87A9+C240-8F07 + cheat + description:Invincibility + code:7E0C4C:21 + cheat + description:Infinite lives - Wolverine + code:7E0B7E:08 + cheat + description:Infinite lives - Cyclops + code:7E0B7F:08 + cheat + description:Infinite lives - Beast + code:7E0B82:08 + cheat + description:Infinite lives - Psylocke + code:7E0B80:08 + cheat + description:Infinite lives - Gambit + code:7E0B81:08 + cheat + description:Use 1 button specials from practice mode in mission mode + code:7E0B89:01 + cheat + description:Lava stops flowing + code:7E1685:DB + +cartridge sha256:363c60f924257bf6465efc32093c7749a0e69ea7234e47ebd4f070e7b0e7035d + title:Yogi Bear (Japan) + cheat + description:Infinite health + code:7E021E:06 + cheat + description:Infinite lives + code:7E021C:09 + cheat + description:Super-jump + code:7E0AB0:00 + cheat + description:Start on Snow Business Stage 1 + code:7E009F:23 + cheat + description:Start on Snow Business Stage 2 + code:7E009F:28 + cheat + description:Start on Snow Business Stage 3 + code:7E009F:2D + cheat + description:Start on Snow Business Stage 4 + code:7E009F:32 + cheat + description:Start on Cave Capers Stage 1 + code:7E009F:37 + cheat + description:Start on Cave Capers Stage 2 + code:7E009F:3C + cheat + description:Start on Cave Capers Stage 3 + code:7E009F:41 + cheat + description:Start on Cave Capers Stage 4 + code:7E009F:46 + cheat + description:Start on Redwood Rendevous Stage 1 + code:7E009F:4B + cheat + description:Start on Redwood Rendevous Stage 2 + code:7E009F:50 + cheat + description:Start on Redwood Rendevous Stage 3 + code:7E009F:55 + cheat + description:Start on Redwood Rendevous Stage 4 + code:7E009F:5A + cheat + description:Start on Water Palaver Stage 1 + code:7E009F:5F + cheat + description:Start on Water Palaver Stage 2 + code:7E009F:64 + cheat + description:Start on Water Palaver Stage 3 + code:7E009F:69 + cheat + description:Start on Water Palaver Stage 4 + code:7E009F:6E + cheat + description:Start on Construction Site Shenanigans Stage 1 + code:7E009F:73 + cheat + description:Start on Construction Site Shenanigans Stage 2 + code:7E009F:78 + cheat + description:Start on Construction Site Shenanigans Stage 3 + code:7E009F:7D + cheat + description:Start on Construction Site Shenanigans Stage 4 + code:7E009F:82 + +cartridge sha256:163399c955e6d813056826e53fc1a7d21d8958e3d11c6384854cc284412caffb + title:Yogi Bear's Cartoon Capers (Europe) + cheat + description:Infinite health + code:7E021E:06 + cheat + description:Infinite lives + code:7E021C:09 + cheat + description:Start on Snow Business Stage 1 + code:7E009F:23 + cheat + description:Start on Snow Business Stage 2 + code:7E009F:28 + cheat + description:Start on Snow Business Stage 3 + code:7E009F:2D + cheat + description:Start on Snow Business Stage 4 + code:7E009F:32 + cheat + description:Start on Cave Capers Stage 1 + code:7E009F:37 + cheat + description:Start on Cave Capers Stage 2 + code:7E009F:3C + cheat + description:Start on Cave Capers Stage 3 + code:7E009F:41 + cheat + description:Start on Cave Capers Stage 4 + code:7E009F:46 + cheat + description:Start on Redwood Rendevous Stage 1 + code:7E009F:4B + cheat + description:Start on Redwood Rendevous Stage 2 + code:7E009F:50 + cheat + description:Start on Redwood Rendevous Stage 3 + code:7E009F:55 + cheat + description:Start on Redwood Rendevous Stage 4 + code:7E009F:5A + cheat + description:Start on Water Palaver Stage 1 + code:7E009F:5F + cheat + description:Start on Water Palaver Stage 2 + code:7E009F:64 + cheat + description:Start on Water Palaver Stage 3 + code:7E009F:69 + cheat + description:Start on Water Palaver Stage 4 + code:7E009F:6E + cheat + description:Start on Construction Site Shenanigans Stage 1 + code:7E009F:73 + cheat + description:Start on Construction Site Shenanigans Stage 2 + code:7E009F:78 + cheat + description:Start on Construction Site Shenanigans Stage 3 + code:7E009F:7D + cheat + description:Start on Construction Site Shenanigans Stage 4 + code:7E009F:82 + +cartridge sha256:90ad69a489194aca7ef7b7fd1d30e0105da4934a81ac8b0333ea20f9248df92d + title:Yoshi's Cookie (USA) + cheat + description:In action mode, passing a stage advances to the next round + code:6D8F-DF3B + cheat + description:Immediately complete current Action level whenever effects switch is turned on (keep switch off to play) + code:D48D-AD36 + cheat + description:All 99 Action rounds available without the secret code + code:14C6-0436 + cheat + description:In VS mode, only 1 win is required instead of 3. P2 always wins the set (2P only) + code:DF86-A71C + cheat + description:In VS mode, the fuses don't count down + code:C2A0-DF48 + cheat + description:In VS mode, play against tougher opponents without the secret code + code:D685-A766+DD86-AF66 + cheat + description:In Puzzle mode, passing a stage advances to the next round + code:DD3C-6738 + cheat + description:Unlimited moves in puzzle mode (turn effects switch off to use up moves if the level becomes impossible) + code:C2EA-671B + +cartridge sha256:12fba2aff04c8e39968e828629ebd16caa314bca397a9418d35fdaffe8188e20 + title:Yoshi's Safari (USA) + cheat + description:Almost infinite health + code:C221-116D+C283-4FAE + cheat + description:Infinite power + code:DD6B-1D00+DD26-11AF + cheat + description:Infinite time + code:C2E9-47DE + cheat + description:Infinite lives + code:C228-376D + cheat + description:Don't lose coins when you miss a jump + code:C28F-3D02 + cheat + description:1 minute for stage 1 instead of 4 + code:DFC9-4F82 + cheat + description:9 minutes for stage 1 + code:DBC9-4F82 + cheat + description:1 minute for stage 2 instead of 4 + code:DFC9-4472 + cheat + description:9 minutes for stage 2 + code:DBC9-4472 + cheat + description:Lose power more quickly + code:DF6B-1D60+DF26-15DF + cheat + description:Lose power more slowly + code:D96B-1D00+D926-11AF + cheat + description:Gain power more quickly + code:DF6C-1460+DF2B-156F + cheat + description:Gain power more slowly + code:4D6C-1400+4D2B-150F + cheat + description:1-up with every coin after you get 10 + code:DBEF-1D6E + cheat + description:1-up with every coin after you get 30 + code:F3EF-1D6E + cheat + description:1-up with every coin after you get 99 + code:14EF-1D6E + cheat + description:Start with 1 life + code:DD67-1D50 + cheat + description:Start with 5 lives + code:D067-1D50 + cheat + description:Start with 10 lives + code:DB67-1D50 + +cartridge sha256:fbe8926fc0149d3e8e2aec20f15640ea6814f4f4b01c3960f3c477f5f17e890f + title:Young Merlin (USA) + cheat + description:Faster Merlin + code:D9B7-14F9 + cheat + description:Slower mine cart + code:D46B-1030 + cheat + description:2 hearts from rainbow water bottle + code:D4C0-CD6F + cheat + description:3 hearts from rainbow water bottle + code:D7C0-CD6F + cheat + description:Start with 6 heart containers (new game) + code:D186-C1D1 + cheat + description:Start with 8 heart containers (new game) + code:D686-C1D1 + cheat + description:Infinite health + code:7EEDDE:02 + +cartridge sha256:b0e74f0fe8d1e7fe2fe404341fea7c68e28f3a0ab78552d5092d413f2ecec417 + title:Ys III - Wanderers from Ys (USA) + cheat + description:Invincibility + code:D6FE-BE7C + cheat + description:Infinite health + code:C2B3-D092 + cheat + description:Infinite Amulet shots + code:D7F3-2358 + cheat + description:Items are free if you have enough money + code:6DEB-D46F+DCEB-D4AF + cheat + description:One hit kills on bosses (except final boss) + code:DDF3-2A5B + cheat + description:Gain experience quicker + code:CBBB-A192 + cheat + description:Gain experience much quicker + code:CBBB-A192+79BB-A1B2 + cheat + description:Start with 100 hit points instead of 20 + code:1082-012E + cheat + description:Start with 200 hit points + code:A682-012E + cheat + description:Start with 488 Gold instead of 1,000 + code:DF8E-00BE + cheat + description:Start with 2,024 Gold + code:D58E-00BE + cheat + description:Start with 9,704 Gold + code:498E-00BE + cheat + description:Start with 20,200 Gold + code:038E-00BE + cheat + description:Start with 40,168 Gold + code:BA8E-00BE + cheat + description:Start with 65,512 Gold + code:EE8E-00BE + cheat + description:Invincibiltiy (alt) + code:7E1AFC:08 + cheat + description:Infinite Gold + code:7E1297:FF+7E1298:FF + cheat + description:255 Max HP + code:7E1295:FF + cheat + description:Max Exp + code:7E1299:FF+7E129A:FF + cheat + description:255 Ring + code:7E1296:FF + cheat + description:255 STR + code:7E129D:FF + cheat + description:255 DEF + code:7E129E:FF + cheat + description:1 Exp point to gain next level + code:7E129B:01 + cheat + description:Have all equipment + code:7E12B1:FF+7E12B2:FF+7E12A0:FF+7E12A8:FF+7E12A1:FF+7E12A2:FF+7E12A3:FF+7E12A4:FF+7E12A5:FF+7E12A6:FF+7E12A7:FF+7E12A9:FF+7E12AA:FF+7E12AB:FF+7E12B3:FF+7E12AC:FF+7E12AD:FF+7E12AE:FF+7E12AF:FF+7E12B0:FF + cheat + description:Have all inventory items + code:7E12BF:FF+7E12C0:FF+7E12C1:FF+7E12C2:FF+7E12C3:FF+7E12C4:FF+7E12B9:FF+7E12BA:FF+7E12BB:FF+7E12BC:FF+7E12BD:FF+7E12BE:FF + cheat + description:Have all statues + code:7E12C5:FF+7E12C6:FF+7E12C7:FF+7E12C8:FF + +cartridge sha256:10d94f1acd8108552eaefe9e26069e5d83e8fc3e847df7af318c2e25b53d39c3 + title:Ys IV - Mask of the Sun (Japan) + cheat + description:Infinite HP + code:7E0973:FF + cheat + description:Infinite GP + code:7E0983:FF+7E0984:FF + cheat + description:Max EXP + code:7E097B:FF+7E097C:FF + +cartridge sha256:d8d14c9f599cf915127440ba22fcbb7c33814f5688c9ae4f8855ed1f6ed42128 + title:Yuu Yuu Hakusho Final - Makai Saikyou Retsuden (Japan) + cheat + description:Infinite health + code:7E0A38:50 + cheat + description:Infinite power + code:7E0A3C:50 + cheat + description:One hit kills + code:7E0F38:00 + cheat + description:Opponent has no power + code:7E0F3C:00 + +cartridge sha256:7d414b7f5941f1eddc35259a22accbbbd7b47c517dfcf8bad86c4dcfa9e50b1e + title:Zero the Kamikaze Squirrel (USA) + cheat + description:Invincibility + code:7E0E2C:02 + cheat + description:Infinite health + code:7E1674:04 + cheat + description:Infinite lives + code:7E1672:06 + cheat + description:Infinite Shurikens + code:7E1676:99 + +cartridge sha256:25414de02c6805ca62574cfb39c23bf292b3d8c4ff33eb8f212ccdbcd61c5ae3 + title:Zool - Ninja of the 'Nth' Dimension (USA) + cheat + description:Invincibility (blinking) + code:7E1D8B:49 + cheat + description:Invincibility + code:7E05DC:FF + cheat + description:Infinite health + code:7E1CF1:FA + cheat + description:Infinite lives + code:7E020C:63 + cheat + description:Infinite time + code:7E1CEF:09 + cheat + description:Infinite continues + code:7E020C:63 + +cartridge sha256:b27e2e957fa760f4f483e2af30e03062034a6c0066984f2e284cc2cb430b2059 + title:Zombies Ate My Neighbors (USA) + cheat + description:Invincibility, hit anywhere, get items from anywhere (do not use martian gun) - both players + code:6DEC-14D4+DD2F-476D+DD8D-37D7+DD8E-C767 + cheat + description:Invincibility - both players + code:DD2F-476D + cheat + description:Infinite health - both players + code:3C20-4D0D + cheat + description:Infinite weapons - both players + code:DD30-1FA7 + cheat + description:Infinite Keys on pick-up + code:DD3F-1DD4 + cheat + description:Infinite special items (except Keys and random Potions) + code:DD39-34D4 + cheat + description:Infinite lives - both players + code:82AA-CF07 + cheat + description:Victims are invincible + code:18CC-37DA + cheat + description:Package of 99 Squirtgun shots worth 999 + code:DBEC-4704 + cheat + description:Package of 20 Soda Pop Cans worth 99 + code:BBE8-44D4 + cheat + description:Package of 20 Tomatoes worth 99 + code:BBE8-4464 + cheat + description:Package of 5 Bazookas worth 999 + code:BBE8-4FA4 + cheat + description:Each First Aid Kit worth 9 on pick-up + code:DBEF-1F04 + cheat + description:Each Key worth 9 on pick-up + code:DBED-1FA4 + cheat + description:Only 1 victim to rescue per level (no bonus for rescuing all victims, game is over if Zombie eats a victim) + code:DF63-14DF + cheat + description:Can advance to next level after getting 1 victim (no bonus for rescuing all victims, game is over if Zombie eats a victim) + code:BAA1-44A4 + cheat + description:Continue with 1/2 health + code:D921-1DD4 + cheat + description:Start with 1/2 health + code:D965-4464 + cheat + description:Start with 10 lives + code:DB66-4DD4 + cheat + description:Start with 7 lives + code:D166-4DD4 + cheat + description:Start with 1 life + code:DD66-4DD4 + cheat + description:Start with 50 shots in Squirtgun + code:DD6B-4DA4 + cheat + description:Start with 100 shots in Squirtgun + code:DD6B-4D64 + cheat + description:Start with 550 shots in Squirtgun + code:D96B-4DA4 + cheat + description:Start with 950 shots in Squirtgun + code:DB6B-4DA4 + cheat + description:Start with Soda Pop Cans instead of Squirtguns (Press B or Y to get item) + code:266B-4704 + cheat + description:Start with Bazookas (Press B or Y to get item) + code:216B-4704 + cheat + description:Start with Tomatoes (Press B or Y to get item) + code:2C6B-4704 + cheat + description:Start with Fire Extinguishers (Press B or Y to get item) + code:A36B-4704 + cheat + description:Start with Ice Pops (Press B or Y to get item) + code:2A6B-4704 + cheat + description:Start with Peppers (Press B or Y to get item) + code:236B-4704 + cheat + description:Start with Martian Bubble Guns (Press B or Y to get item) + code:2D6B-4704 + cheat + description:Start with Weed-eaters (Press B or Y to get item) + code:246B-4704 + cheat + description:Start with Ancient Artifacts (Press B or Y to get item) + code:206B-4704 + cheat + description:Start with Plates (Press B or Y to get item) + code:3D6B-4704 + cheat + description:Start with Silverware (Press B or Y to get item) + code:346B-4704 + cheat + description:Start with Footballs (Press B or Y to get item) + code:306B-4704 + cheat + description:Start with 9 First Aid Kits instead of 1 + code:DB6B-4F04 + cheat + description:Start with Speed Shoes instead of First Aid Kit (Press B or Y to get item) + code:D36C-4DD4 + cheat + description:Start with a Monster Potion (Press B or Y to get item) + code:FD6C-4DD4 + cheat + description:Start with a Ghost Potion (Press B or Y to get item) + code:F46C-4DD4 + cheat + description:Start with a Random Potion (Press B or Y to get item) + code:F06C-4DD4 + cheat + description:Start with a Pandora's box (Press B or Y to get item) + code:FA6C-4DD4 + cheat + description:Start with a Skeleton key (Press B or Y to get item) + code:F36C-4DD4 + cheat + description:Start with a Decoy (Press B or Y to get item) + code:4D6C-4DD4 + cheat + description:Start on level 2 + code:D46E-1D0F + cheat + description:Start on level 3 + code:D76E-1D0F + cheat + description:Start on level 4 + code:D06E-1D0F + cheat + description:Start on level 5 + code:D96E-1D0F + cheat + description:Start on level 6 + code:D16E-1D0F + cheat + description:Start on level 7 + code:D56E-1D0F + cheat + description:Start on level 8 + code:D66E-1D0F + cheat + description:Start on level 9 + code:DB6E-1D0F + cheat + description:Start on level 10 + code:DC6E-1D0F + cheat + description:Start on level 11 + code:D86E-1D0F + cheat + description:Start on level 12 + code:DA6E-1D0F + cheat + description:Start on level 13 + code:D26E-1D0F + cheat + description:Start on level 14 + code:D36E-1D0F + cheat + description:Start on level 15 + code:DE6E-1D0F + cheat + description:Start on level 16 + code:FD6E-1D0F + cheat + description:Start on level 17 + code:FF6E-1D0F + cheat + description:Start on level 18 + code:F46E-1D0F + cheat + description:Start on level 19 + code:F76E-1D0F + cheat + description:Start on level 20 + code:F06E-1D0F + cheat + description:Start on level 21 + code:F96E-1D0F + cheat + description:Start on level 22 + code:F16E-1D0F + cheat + description:Start on level 23 + code:F56E-1D0F + cheat + description:Start on level 24 + code:F66E-1D0F + cheat + description:Start on level 25 + code:FB6E-1D0F + cheat + description:Start on level 26 + code:FC6E-1D0F + cheat + description:Start on level 27 + code:F86E-1D0F + cheat + description:Start on level 28 + code:FA6E-1D0F + cheat + description:Start on level 29 + code:F26E-1D0F + cheat + description:Start on level 30 + code:F36E-1D0F + cheat + description:Start on level 31 + code:FE6E-1D0F + cheat + description:Start on level 32 + code:4D6E-1D0F + cheat + description:Start on level 33 + code:4F6E-1D0F + cheat + description:Start on level 34 + code:446E-1D0F + cheat + description:Start on level 35 + code:476E-1D0F + cheat + description:Start on level 36 + code:406E-1D0F + cheat + description:Start on level 37 + code:496E-1D0F + cheat + description:Start on level 38 + code:416E-1D0F + cheat + description:Start on level 39 + code:456E-1D0F + cheat + description:Start on level 40 + code:466E-1D0F + cheat + description:Start on level 41 + code:4B6E-1D0F + cheat + description:Start on level 42 + code:4C6E-1D0F + cheat + description:Start on level 43 + code:486E-1D0F + cheat + description:Start on level 44 + code:4A6E-1D0F + cheat + description:Start on level 45 + code:426E-1D0F + cheat + description:Start on level 46 + code:436E-1D0F + cheat + description:Start on level 47 + code:4E6E-1D0F + cheat + description:Start on level 48 + code:7D6E-1D0F + cheat + description:Start on bonus level Son of Dr. Tongue + code:746E-1D0F + cheat + description:Start on bonus level Day of the Tentacle + code:776E-1D0F + cheat + description:Start on bonus level Someplace Very Warm + code:706E-1D0F + cheat + description:Start on bonus level Curse of the Pharaohs + code:796E-1D0F + cheat + description:Start on bonus level Mushroom Men + code:716E-1D0F + cheat + description:Start on bonus level Cheerleaders vs. the Monsters + code:756E-1D0F + cheat + description:Start on credit level Monsters Among Us + code:7F6E-1D0F + cheat + description:Infinite health - P1 + code:7E1CB8:0A + cheat + description:Infinite health - P2 + code:7E1CBA:0A + cheat + description:Infinite lives - P1 + code:7E1D4C:03 + cheat + description:Infinite lives - P2 + code:7E1D4E:03 + cheat + description:Skip Konami and LucasArts intro screens + code:7E0C7C:01 + cheat + description:Only 1 victim to rescue to advance + code:7E1D52:01 + cheat + description:Always have Shoes effect - P1 + code:7E0155:FF + cheat + description:Always have Shoes effect - P2 + code:7E02D5:FF + cheat + description:Infinite Bazooka - P1 + code:7E1CD6:50 + cheat + description:Infinite Bazooka - P2 + code:7E1CF6:50 + cheat + description:Infinite Berries - P1 + code:7E1CDA:50 + cheat + description:Infinite Berries - P2 + code:7E1CFA:50 + cheat + description:Infinite Cold Potion - P1 + code:7E1D12:09 + cheat + description:Infinite Cold Potion - P2 + code:7E1D32:09 + cheat + description:Infinite Dummy Clown - P1 + code:7E1D20:09 + cheat + description:Infinite Dummy Clown - P2 + code:7E1D40:09 + cheat + description:Infinite Extinguisher - P1 + code:7E1CCE:50 + cheat + description:Infinite Extinguisher - P2 + code:7E1CEE:50 + cheat + description:Infinite Flamethrower - P1 + code:7E1CE6:50 + cheat + description:Infinite Flamethrower - P2 + code:7E1D06:50 + cheat + description:Infinite Footballs - P1 + code:7E1CE4:50 + cheat + description:Infinite Footballs - P2 + code:7E1D04:50 + cheat + description:Infinite Holy Cross - P1 + code:7E1CD4:50 + cheat + description:Infinite Holy Cross - P2 + code:7E1CF4:50 + cheat + description:Infinite Keys - P1 + code:7E1D0C:09 + cheat + description:Infinite Keys - P2 + code:7E1D2C:09 + cheat + description:Infinite Martian Gun - P1 + code:7E1CD0:50 + cheat + description:Infinite Martian Gun - P2 + code:7E1CF0:50 + cheat + description:Infinite Medical Kit - P1 + code:7E1D1A:09 + cheat + description:Infinite Medical Kit - P2 + code:7E1D3A:09 + cheat + description:Infinite Monster Potion - P1 + code:7E1D10:09 + cheat + description:Infinite Monster Potion - P2 + code:7E1D30:09 + cheat + description:Infinite Pandoras Box - P1 + code:7E1D1C:09 + cheat + description:Infinite Pandoras Box - P2 + code:7E1D3C:09 + cheat + description:Infinite Plates - P1 + code:7E1CE0:50 + cheat + description:Infinite Plates - P2 + code:7E1D00:50 + cheat + description:Infinite Popsicles - P1 + code:7E1CDC:50 + cheat + description:Infinite Popsicles - P2 + code:7E1CFC:50 + cheat + description:Infinite Random A Potion - P1 + code:7E1D14:09 + cheat + description:Infinite Random A Potion - P2 + code:7E1D34:09 + cheat + description:Infinite Random B Potion - P1 + code:7E1D16:09 + cheat + description:Infinite Random B Potion - P2 + code:7E1D36:09 + cheat + description:Infinite Shoes - P1 + code:7E1D0E:09 + cheat + description:Infinite Shoes - P2 + code:7E1D2E:09 + cheat + description:Infinite Silverware - P1 + code:7E1CE2:50 + cheat + description:Infinite Silverware - P2 + code:7E1D02:50 + cheat + description:Infinite Skeleton Key - P1 + code:7E1D1E:09 + cheat + description:Infinite Skeleton Key - P2 + code:7E1D3E:09 + cheat + description:Infinite Soda Bombs - P1 + code:7E1CD8:50 + cheat + description:Infinite Soda Bombs - P2 + code:7E1CF8:50 + cheat + description:Infinite Squirt Gun - P1 + code:7E1CCC:50 + cheat + description:Infinite Squirt Gun - P2 + code:7E1CEC:50 + cheat + description:Infinite Weed Wacker - P1 + code:7E1CD2:50 + cheat + description:Infinite Weed Wacker - P2 + code:7E1CF2:50 + +cartridge sha256:18746d4607424feca05aee056c3ed5f840195c792409881e9145d4bd96800dbd + title:Addams Family, The - Pugsley's Scavenger Hunt (USA, Europe) + cheat + description:Invincibility + code:C99-15C-3BE + cheat + description:Infinite health + code:BE9-15C-3BE + cheat + description:Infinite hearts + code:009-11C-E6D + cheat + description:Infinite lives + code:FA4-28F-4C1 + cheat + description:Infinite lives (alt) + code:BE4-27F-19E + cheat + description:When game begins, go through any door, enter secret bonus room, disable to exit room + code:AF3-DEE-7F1+3C3-DFE-916+7D3-E1E-197 + cheat + description:Lose 1 heart to become invincible + code:FAA-DCF-4C1 + cheat + description:Start each life with 1 energy heart + code:01F-E98-E66 + cheat + description:Start each life with 5 energy hearts + code:05F-E98-E66 + cheat + description:Start with 1 life + code:012-17F-F7E + cheat + description:Start with 10 lives + code:0A2-17F-F7E + +cartridge sha256:f267738e785f43a09c92511bcbb7f16d2e8acbe43b36f75bee35ff3fb0c21621 + title:Addams Family, The (USA) + cheat + description:Invincibility + code:BEA-DAB-4C1+C99-D7F-4C1 + cheat + description:Infinite health + code:BEF-35E-3BE + cheat + description:Infinite lives + code:BED-CEA-3BE + cheat + description:Infinite weapon + code:BE8-688-3BE + +cartridge sha256:7771919d5f5a114fb8685345eab290be22e99c59d8798ed9c5f29e3079c11c56 + title:Adventure Island (USA, Europe) + cheat + description:Invincibility + code:BE6-53E-4C1 + cheat + description:Infinite time + code:BE6-90E-3BE + cheat + description:Infinite lives + code:BEA-C88-3BE + +cartridge sha256:bbb38ee1e9877404dd999ef7067aa238a1039ca603b987f8adeff4488e318331 + title:Adventure Island II - Aliens in Paradise (USA, Europe) + cheat + description:Invincibility + code:C9A-D8E-4C1 + cheat + description:Infinite time + code:C9E-2CF-4C1 + cheat + description:Infinite lives + code:006-DDB-E6E + cheat + description:Infinite lives (alt) + code:BE6-DCB-B31 + cheat + description:No gradual loss of energy, but can still be drained by obstacles and enemies + code:00E-28F-E6E + cheat + description:Once you collect any non-throwable object, you can't lose it from menu + code:00D-51A-E6E + cheat + description:Start with 1 of each power-up + code:3C0-37B-5D4 + cheat + description:Start with 1 life + code:000-6DB-E66 + cheat + description:Start with 6 lives + code:050-6DB-E66 + cheat + description:Start with 9 lives + code:080-6DB-E66 + cheat + description:Start on level 1-4 + code:080-57B-E6E + +cartridge sha256:50c3a2193005c9134699ab00de16510fb946db10cdbc33bfacd8a3132926b72e + title:Adventures of Pinocchio, The (USA) (Proto) + cheat + description:Invincibility + code:C94-C0E-6E9 + +cartridge sha256:ee582fc5f302c430556703c553c3a49db8e05847ba9b13d0f6bc018657ac8593 + title:Adventures of Rocky and Bullwinkle and Friends, The (USA) + cheat + description:Invincibility + code:C94-4CE-E69 + cheat + description:Invincibility after first hit + code:FA4-28E-4C1 + cheat + description:Infinite energy + code:FA4-96E-4C1 + cheat + description:Die in one hit + code:014-53E-08B + cheat + description:Start with 1 life + code:001-5CA-E62 + cheat + description:Start with 10 lives + code:091-5CA-E62 + cheat + description:Start with 15 lives + code:0E1-5CA-E62 + cheat + description:Start with 1 mooseberry - 1st life + code:001-61A-E66 + cheat + description:Start with 5 mooseberries - 1st life + code:041-61A-E66 + cheat + description:Start with 10 mooseberries - 1st life + code:091-61A-E66 + cheat + description:Start with 1 mooseberry - 2nd life + code:004-BCE-E66 + cheat + description:Start with 5 mooseberries - 2nd life + code:044-BCE-E66 + cheat + description:Start with 10 mooseberries - 2nd life + code:094-BCE-E66 + +cartridge sha256:e946c9e9c819cb9ba37eb1718903aa3cd5ea101d5890e27681b370a44fe0f1d8 + title:Adventures of Star Saver, The (USA, Europe) + cheat + description:Invincibility (blinking) + code:C9B-D9E-4C1 + cheat + description:Infinite lives + code:BE1-A7E-3BE + cheat + description:Infinite life ropes + code:003-89D-F71 + cheat + description:Infinite shields on pick-up + code:001-63D-F71+00B-B7E-F71+00B-DBE-F71 + cheat + description:49 life ropes on pick-up + code:75C-94E-3BA + cheat + description:Start with all power-ups (except shields) - 1st life only + code:3C1-7FE-5D4 + cheat + description:Start with 2 lives + code:021-99E-E66 + cheat + description:Start with 4 lives + code:041-99E-E66 + cheat + description:Start with 6 lives + code:061-99E-E66 + +cartridge sha256:cb1d45fca310ef4b7013d094663bddcd209362f272bb3e54ce10540828c8c212 + title:Aerostar (USA, Europe) + cheat + description:Invincibility + code:03A-ADD-A21+17A-AED-2AA+F07-07E-192 + cheat + description:Infinite lives + code:F06-F1E-6E9 + cheat + description:Infinite jump + code:BE8-70E-6E9 + +cartridge sha256:8e45c7d6b5498d4048653e92b2a792bb2eea00b2897a7711fb7be1b6bed0534f + title:Akumajou Dracula - Shikkoku Taru Zensoukyoku - Dark Night Prelude (Japan) (SGB Enhanced) + cheat + description:Fast walk left + code:11D-F3B-F7D + cheat + description:Fast walk right + code:11D-CCB-F7D + cheat + description:Fast jump left + code:114-2CA-F7D + cheat + description:Fast jump right + code:114-0BA-F7D + +cartridge sha256:4940bf228fb2095daa6b382d84ebd0cf05cd81fc2e6e5244a03ab458593e53f5 + title:Aladdin (USA) (SGB Enhanced) + cheat + description:Infinite health + code:BED-CAF-A28 + cheat + description:Infinite lives + code:BEC-E5E-19E + cheat + description:Infinite Apples + code:BE1-6DD-19E + +cartridge sha256:944df9d20c715099ef6bf0e418d928684b284d4a4562391a661a7978fa7f5417 + title:Alfred Chicken (USA) + cheat + description:Invincibility + code:BE5-46E-6E9 + cheat + description:Infinite time + code:BEB-C2E-D51 + cheat + description:Infinite lives + code:BEB-E9E-A24 + +cartridge sha256:4790f55d0917f4418c63d29c5c528362b1c7ae39546f6fc3ae94e867d1e9f270 + title:Alien 3 (USA, Europe) + cheat + description:Almost infinite health + code:FA7-68E-4C1 + cheat + description:Infinite tries + code:FA6-92E-4C1 + cheat + description:Infinite shots per clip on pick-up + code:00F-9CD-E65 + cheat + description:Infinite magazine clips on pick-up + code:FAB-45D-4C1 + cheat + description:50 shots per magazine clip + code:32A-3CA-19A + cheat + description:75 shots per magazine clip + code:4BA-3CA-19A + cheat + description:100 shots per magazine clip + code:64A-3CA-19A + cheat + description:Start with 1/2 health + code:8E4-42D-195 + cheat + description:Start with 4 tries + code:04B-27E-E66 + cheat + description:Start with 6 tries + code:06B-27E-E66 + cheat + description:Start with 10 tries + code:0AB-27E-E66 + +cartridge sha256:073f82f8bf4ab9d15569b5a7a4aa152351c177b9072a9481563b26562215f55b + title:Alien Olympics (Europe) + cheat + description:Meter never decreases + code:C9D-7DB-800 + cheat + description:Hyper velocity + code:BED-7AB-A24 + cheat + description:Freeze time + code:BEC-6DA-19A + +cartridge sha256:e1a71b44a1c5dcacfe90e76907766fd48518482950531bee34208114d4a03e53 + title:Alien vs Predator - The Last of His Clan (USA) + cheat + description:Infinite lives + code:BEF-D4D-3BE + cheat + description:Infinite energy + code:BE4-EFF-19E + cheat + description:Infinite HP + code:BEB-BAC-4C1 + +cartridge sha256:ed8070e011713527bdc03e2b9cec9f9c4a7e3aaa00e57e8786a186b265da1bb2 + title:Alleyway (World) + cheat + description:Infinite lives + code:BE7-EEF-19E + +cartridge sha256:04c5507efe0beb40ea1a887538bd8a04acc70622bf9ef800951a71f4804c9cbc + title:All-Star Baseball 99 (USA) + cheat + description:Infinite time + code:006-5E9-E6E + cheat + description:Computer's 3-pt. shots worth 25 points + code:191-1FD-E66 + cheat + description:Computer's 3-pt. shots worth 17 points + code:111-1FD-E66+111-18D-E6D + cheat + description:Computer makes almost all shots + code:36E-F7D-191+096-F8D-F7A + cheat + description:Computer can't score against you + code:341-15D-3B2+001-16D-E6D + cheat + description:Shot clock for human player is 9 seconds - 1-on-1 game + code:095-FB9-7FA+093-3DD-7FA+095-C49-7FA + +cartridge sha256:4f6450321ee163d5fd8a942816b10af1ce41bbcad62185a550c97b16cac125a1 + title:Altered Space - A 3-D Alien Adventure (USA) + cheat + description:Infinite energy (air) + code:3A4-F1E-B31 + +cartridge sha256:db4e590899aab75bceb31e84a2ec77c34b561838a61fd9dc9fda004a0507a01c + title:Amazing Penguin (USA, Europe) + cheat + description:Infinite lives + code:BE2-28D-19E + cheat + description:Infinite time + code:BE6-C4E-3BE + +cartridge sha256:3f0688ed9219c44ce133647f0668cde50fdcba7ed8f04c34c3a0fc5ce596bfe5 + title:Asteroids (USA, Europe) + cheat + description:Infinite lives + code:003-83F-3BE + cheat + description:No extra rocks as you go up levels + code:00A-7ED-3BA + cheat + description:Rocks go thru you unless you move from the middle + code:01C-B4D-F76+003-9CF-3BE + cheat + description:Start with 1 life + code:013-15F-E66 + cheat + description:Start with 5 lives + code:053-15F-E66 + cheat + description:Start with 9 lives + code:093-15F-E66 + +cartridge sha256:d5306853c8dc7d402808cc340064fdf48d930bbc5a531c8ece3661bfa7f7ff55 + title:Atlantis - The Lost Empire (USA, Europe) + cheat + description:Infinite energy + code:FA2-ACA-4C1 + cheat + description:Infinite lives + code:FAC-3AE-4C1 + cheat + description:Start with 9 lives + code:094-3EC-E66 + +cartridge sha256:2df8eb5d48a204d9609e0c12fed81304cc0b23421c5015ab2296d51ffc8b36ad + title:Atomic Punk (USA) + cheat + description:Invincibility and infinite time + code:092-5EF-F77+752-5DF-B38+919-76F-195 + +cartridge sha256:ac3656cb5b86c13ad67a486d11d21643fdec306500d989fbd770b5939bab22f0 + title:Attack of the Killer Tomatoes (USA, Europe) + cheat + description:Infinite health + code:00A-DBF-3BE + cheat + description:Infinite lives + code:FA9-45C-4C1 + +cartridge sha256:0d80b2ad776053f50c3eb0e0e32c675f24acf94923bf3ac4c156c7c28bc76a6e + title:Avenging Spirit (USA, Europe) + cheat + description:Infinite energy except if weapon is used against you + code:FA5-AFC-4C1+FAE-C2D-4C1 + cheat + description:Infinite L energy except against spikes + code:FAE-B5D-4C1 + cheat + description:Start with 1/2 energy + code:0A3-2BC-B3A + cheat + description:Start with 1/4 energy + code:053-2BC-B3A + cheat + description:Start with 3/4 energy + code:0F3-2BC-B3A + cheat + description:Start on level 2 (brings you back to level 2) + code:029-B9C-E6E + cheat + description:Start on level 4 (brings you back to level 2) + code:049-B9C-E6E + cheat + description:Start on level 6 (brings you back to level 2) + code:069-B9C-E6E + +cartridge sha256:1b48b454bb421836c33c2d572c61f69145a077ebcecbf8194dfb05fc6581ff82 + title:Balloon Kid (USA, Europe) + cheat + description:Invincibility against fire + code:006-04A-C4E + +cartridge sha256:c71663c9172c69b3daded65aaaa3735d1f50379a471af345e8421a6a6c9aaa98 + title:Barbie - Game Girl (USA, Europe) + cheat + description:Infinite HP + code:FAA-A5C-4C1 + cheat + description:Infinite continues + code:FAB-959-4C1 + cheat + description:1 continue + code:017-ADD-E66 + cheat + description:4 continues + code:047-ADD-E66 + cheat + description:8 continues + code:087-ADD-E66 + cheat + description:Start with 2 HP + code:027-7AD-F7E + cheat + description:Start with 4 HP + code:047-7AD-F7E + cheat + description:Start with 8 HP + code:087-7AD-F7E + +cartridge sha256:86e5b7037d7c61248adfdc316d61b5c58fe46c5d3fe376bcdfeda9d6538b197d + title:Bart Simpson's Escape from Camp Deadly (USA, Europe) + cheat + description:Infinite health + code:FA7-FAF-4C1 + +cartridge sha256:0eedbdd6530f30adcc8ee88b32e852b7983de8bba8122ddd2c1adaf2805a454c + title:Bases Loaded for Game Boy (USA) + cheat + description:No walks + code:00C-63B-19A + cheat + description:1 ball and you walk + code:00C-66B-F7A + cheat + description:2 balls and you walk + code:02C-66B-F7A + cheat + description:3 balls and you walk + code:03C-66B-F7A + cheat + description:5 balls and you walk + code:04C-66B-F7A + cheat + description:Outs aren't counted (base runners will still be taken out) + code:00C-77B-19A + cheat + description:Number of outs to retire the side varies + code:003-8F8-E66 + cheat + description:Strikes aren't counted + code:00C-43B-3BA + cheat + description:1 strike and you're out + code:01C-46B-E66 + cheat + description:2 strikes and you're out + code:02C-46B-E66 + cheat + description:5 strikes and you're out + code:05C-46B-E66 + cheat + description:No scoring - disable to score + code:008-1FF-E6E+008-11F-E6E + +cartridge sha256:9ac1f4a299d32ba21cf65f67ab210afeb4c629adbd8e5779f76b6667ca3a0a4a + title:Batman - The Animated Series (USA, Europe) + cheat + description:Almost invincible - disable if you get stuck + code:215-92D-D5D + cheat + description:Infinite energy + code:005-EFD-3B7 + cheat + description:Infinite batarangs + code:00B-A3D-3BE + cheat + description:One hit kills on most enemies + code:AF6-15E-A2C + cheat + description:Each batarang pick-up is worth 9 + code:09A-70B-F7E + cheat + description:Most enemies don't die + code:006-16E-3B7 + cheat + description:Most enemies are harder to kill + code:0AF-CDB-E62 + cheat + description:Start with 7 batarangs + code:004-96D-5D4+FA4-9AD-4C1 + cheat + description:Start with very little energy + code:014-8ED-F76 + cheat + description:Start with about half energy + code:044-8ED-F76 + cheat + description:Start with about 2x energy + code:0E4-8ED-F76 + +cartridge sha256:152fc252bba7130e786d408eed310b3009b8e05834f8003dfbf514ec804cbaea + title:Batman - Return of the Joker (USA, Europe) + cheat + description:Invincibile against enemies + code:004-ADA-A2E+C64-B2A-7F1 + cheat + description:Infinite batarangs on pick-up + code:009-96E-19E + cheat + description:Infinite continues + code:00A-B5D-F75 + cheat + description:Select any weapon from menu + code:006-BCA-7F1 + cheat + description:5 Batarangs on pick-up + code:05D-A0B-C42 + cheat + description:20 Batarangs on pick-up + code:14D-A0B-C42 + cheat + description:40 Batarangs on pick-up + code:28D-A0B-C42 + cheat + description:1 continue + code:022-07F-F7E + cheat + description:9 continues + code:0A2-07F-F7E + cheat + description:Start with max of 3 HP + code:O62-01F-C42 + cheat + description:Start with max of 8 HP + code:102-01F-C42 + +cartridge sha256:b9909506f566ea7998d6170e9610bad62dbda7d38e42830cd187592e262acfed + title:Battle Unit Zeoth (USA, Europe) + cheat + description:Infinite health + code:F02-33E-6E9 + +cartridge sha256:dfa8ec0354c2c364398686cac91545dd2729ab4e0784e6f0b3a23cfe2f7d253b + title:Battletoads (USA, Europe) + cheat + description:Infinite lives and energy + code:FAC-CAF-4C1+007-B0E-F71 + cheat + description:Infinite continues + code:007-C2E-3BE + cheat + description:Keep axe after dying + code:FAD-918-4C1 + cheat + description:Big arms that hack at you from caves in level 1 do not move + code:005-42E-E6E + cheat + description:1 continue + code:017-F28-E66 + cheat + description:5 continues + code:057-F28-E66 + cheat + description:10 continues + code:0A7-F28-E66 + cheat + description:Start with 1 life + code:007-ED8-E66 + cheat + description:Start with 6 lives + code:O57-ED8-E66 + cheat + description:Start with 10 lives + code:097-ED8-E66 + cheat + description:Start with 2 extra HP - after 1st life + code:0EE-388-D5A + cheat + description:Start 1st life with 2 extra HP + code:0E3-26F-D5A + cheat + description:Start 1st life with 1/2 energy + code:063-26F-D5A + cheat + description:Start with only 1/2 energy - after 1st life + code:06E-388-D5A + +cartridge sha256:e10716e26a1b4edddc8c8fbf24cdad4decd054e555c77a6c0cd64fe283fa2287 + title:Battletoads in Ragnarok's World (USA) + cheat + description:Invincibility - beat'em up levels + code:EAC-FDD-081 + cheat + description:Infinite health + code:FA8-71F-4C1 + cheat + description:Infinite lives + code:7EA-31E-3BE + +cartridge sha256:ffb240c74aac4527af2c268e1d7cf4f1b44229ff624d22966b5679e301617465 + title:Beast Fighter (Asia) (Unl) + cheat + description:Invincibility + code:007-F6A-C49+008-00A-E69+017-FFA-E6A+3E7-FEA-191 + cheat + description:Infinite time + code:C9D-B6D-C49 + cheat + description:One hit kills on bosses + code:006-FAB-E62 + +cartridge sha256:436918dc75ffe606f458206caad6c063369ecbf650afcf96499eb98b2b85a72f + title:Beetlejuice (USA) + cheat + description:Infinite health + code:FA7-E4C-4C1 + cheat + description:Infinite lives + code:FA7-EFC-4C1 + +cartridge sha256:378435aa66290a4d8a930e000eddf08dcb7b00fd36341991b0abedc488bb8c5d + title:Bill Elliott's NASCAR Fast Tracks (USA) + cheat + description:Start with burst of speed + code:XX1-069-19A + cheat + description:Infinite fuel + code:004-65A-3BE + cheat + description:Collisons with cars don't affect speed + code:00D-46B-3BE + cheat + description:Collisions barely affect speed + code:003-C5B-3B7+002-3FA-3B7+000-BDA-19E + cheat + description:Start with 1 lap - ignore lap timer and counter + code:1E7-31B-B37+027-32B-A26 + cheat + description:Start with 3 laps - ignore lap timer and counter + code:1E7-31B-B37+047-32B-A26 + cheat + description:Start with 9 laps - ignore lap timer and counter + code:1E7-31B-B37+0A7-32B-A26 + +cartridge sha256:692e62d9e0048350256ee124d55c6ef225dc2bb54e0808fd882312d4dcaf0f28 + title:Bionic Commando (USA) + cheat + description:Infinite energy + code:FAE-6EB-4C1 + cheat + description:Infinite lives + code:006-0AE-915 + cheat + description:Infinite continues + code:004-04E-915 + cheat + description:2 continues + code:024-818-E66 + cheat + description:4 continues + code:044-818-E66 + cheat + description:6 continues + code:064-818-E66 + cheat + description:Start with 8 energy + code:845-E0E-5D4 + cheat + description:Start with 2 lives + code:024-0EE-E66 + cheat + description:Start with 4 lives + code:044-0EE-E66 + cheat + description:Start with 6 lives + code:064-0EE-E66 + +cartridge sha256:9338af642104f7f286687b2e6e55759917c0db35bc89ef398a92c18570bff681 + title:Blades of Steel (USA) + cheat + description:Set length of game to 1:00 + code:011-65B-6EA + cheat + description:Set length of game to 3:00 + code:031-65B-6EA + cheat + description:Set length of game to 9:00 + code:091-65B-6EA + cheat + description:Opponent's energy doesn't go up again and yours does + code:007-938-19A + cheat + description:Invincible in fights + code:FA7-9F8-4C1 + cheat + description:3 penalty shots in shoot-out + code:035-B6A-F7E + cheat + description:5 penalty shots in shoot-out + code:055-B6A-F7E + cheat + description:9 penalty shots in shoot-out + code:095-B6A-F7E + +cartridge sha256:04aeb80ff35bd863c3922ad9b8cac7ee379e78feac4ce3cef2d58ccca142fc03 + title:Blues Brothers, The (USA, Europe) + cheat + description:Infinite energy + code:00A-F29-3B7 + cheat + description:Infinite encores + code:FA8-05F-4C1 + cheat + description:Start with 3 encores (continues) + code:033-7CF-E62 + cheat + description:Start with 7 encores + code:073-7CF-E62 + cheat + description:Start with 9 encores + code:093-9CF-E62 + cheat + description:Start with 5 lives + code:050-15B-E62 + cheat + description:Start with 7 lives + code:070-15B-E62 + cheat + description:Start with 9 lives + code:090-15B-E62 + +cartridge sha256:195f5a9e97bfec6f071bfd6b82a39ffa25185b687a26a1f2937f9718c4d4d16e + title:Boggle Plus (USA) + cheat + description:Infinite time + code:005-AFD-E6E + cheat + description:1-minute game + code:016-BCD-E66 + cheat + description:5-minute game + code:056-BCD-E66 + cheat + description:9-minute game + code:096-BCD-E66 + cheat + description:Can re-use shaded letters + code:D48-82A-E61 + cheat + description:Can select any letter on the board - letters don't have to be next to each other + code:30E-A9A-4CA + cheat + description:Boggle - 1 and 2 letter words allowed + code:01B-4CA-E66 + cheat + description:Boggle - Minimum word length 4 letters + code:04B-4CA-E66 + cheat + description:Big Boggle - 1 to 3 letter words allowed + code:01B-8FA-F7A + cheat + description:Big Boggle - Minimum word length 5 letters + code:05B-8FA-F7A + +cartridge sha256:beca58b71a27884d2c2820da0c7eb806fa945b2fab66da271588281e03153900 + title:Bomb Jack (Europe) + cheat + description:Infinite lives + code:F04-79F-6E9 + +cartridge sha256:604db636c45af3cd1fec52e206701a8969a8a3e610df281f7461769bd86729ea + title:Bomber Man GB 3 (Japan) (SGB Enhanced) + cheat + description:Invincibility + code:02C-AEB-E6E + cheat + description:Infinite lives + code:005-17E-19E + cheat + description:Freeze timer + code:009-E0D-19E + cheat + description:Maximum Bombs placable + code:185-158-6EA + cheat + description:Maximum blast range + code:185-238-6EA + +cartridge sha256:6081309e7f5b63e4f6694965060c68baf82a775eb18e667c2c89898096e6e3d8 + title:Bonk's Adventure (USA) + cheat + description:Infinite energy + code:005-13B-F7D + cheat + description:Infinite lives + code:007-99D-D5D + cheat + description:Start with 3 lives, 1st life as Mad Bonk + code:021-AFF-E66+001-B3F-5D4 + cheat + description:Start 1st life as Turtle Bonk + code:021-AFF-E66+001-B3F-5D4 + cheat + description:Start with 8 lives + code:071-AFF-E66 + cheat + description:Start with 10 lives + code:091-AFF-E66 + +cartridge sha256:9053443a6c786a54bebc2fa9c10acd3875887134c953e5bdf0a07dc554721fb6 + title:Bo Jackson - Two Games in One (USA) + cheat + description:Baseball - 1 ball and you walk + code:01F-13C-F7A + cheat + description:Baseball - 2 balls and you walk + code:02F-13C-F7A + cheat + description:Baseball - 5 balls and you walk + code:05F-13C-F7A + cheat + description:Baseball - Strikes aren't counted - ignore message, you need 4 balls to walk + code:00E-C5C-3BA + cheat + description:Baseball - Outs aren't counted + code:003-E88-3BA + cheat + description:Baseball - 1 strike and you're out + code:01E-87C-E66 + cheat + description:Baseball - 2 strikes and you're out + code:02E-87C-E66 + cheat + description:Baseball - No scoring - disable to score + code:008-3C8-3BA+008-268-3BA + cheat + description:Football - Infinite time + code:F05-6EC-6E9 + cheat + description:Football - Infinite timeouts + code:000-12A-3BE + cheat + description:Football - Always 1st down + code:F07-D0B-6E9 + cheat + description:Football - Start with 1 timeout + code:010-68B-E66 + cheat + description:Football - Start with 2 timeouts + code:020-68B-E66 + cheat + description:Football - Start with 10 timeouts + code:0A0-68B-E66 + +cartridge sha256:29f17b604be580c0132a6d0bd7a966c82930069ca82f83798c955d532c6b4694 + title:Bubble Bobble Part 2 (USA, Europe) + cheat + description:Infinite hearts + code:FAB-CEE-4C1 + cheat + description:Defeat one enemy to go to next level + code:AFE-33A-19E + cheat + description:No big bubbles appear + code:C97-8AE-E66 + cheat + description:Run into 1 enemy and you remain invincible for the rest of the game + code:FA5-58E-4C1+FAB-46E-4C1+FAB-63E-4C1 + cheat + description:Start with 1 heart + code:015-5CE-E66 + cheat + description:Start with 6 hearts + code:065-5CE-E66 + cheat + description:Start with 9 hearts + code:095-5CE-E66 + cheat + description:Start on round 20 + code:3E8-39F-081+138-3AF-D5E+008-3BF-E6D + cheat + description:Start on round 40 + code:3E8-39F-081+278-3AF-D5E+008-3BF-E6D + cheat + description:Start on round 60 + code:3E8-39F-081+3B8-3AF-D5E+008-3BF-E6D + +cartridge sha256:cf1a8d9c9d4fc9e58740f6e008e5280ff2831c099aecab642e64e5195c0ad0bc + title:Bugs Bunny Crazy Castle 2, The (USA) + cheat + description:Invincibility + code:C92-899-4C1 + cheat + description:Infinite lives + code:BE6-00E-19E + +cartridge sha256:2f4254faaa4bda89486c4820c601917cd034c7965eae075ba81acef4295fa8bd + title:BurgerTime Deluxe (World) + cheat + description:Invincibility + code:C9E-98D-3B2 + cheat + description:Infinite lives + code:FE5-CAE-B31 + cheat + description:Infinite weapon + code:FEB-76D-B31 + +cartridge sha256:f0b147eb3429b1b480424a31eb2d800b5676d01a701b494b2c9e9d2de63d31c5 + title:Captain America and the Avengers (USA) + cheat + description:Infinite energy + code:005-CCE-3B7 + cheat + description:Enemy bullets do very little damage + code:017-748-D5A + cheat + description:Enemy bullets do more damage + code:197-748-D5A + cheat + description:Enemy bullets do much more damage + code:337-748-D5A + cheat + description:Start with energy at 153 + code:99A-29F-7FB + cheat + description:Start with energy at 255 + code:FFA-29F-7FB + cheat + description:Start with energy at 34 + code:22A-29F-7FB + cheat + description:Start with 1 lives + code:011-DDF-E66 + cheat + description:Start with 10 lives + code:0A1-DDF-E66 + cheat + description:Start on stage 1-2 + code:3E3-A8F-912+013-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 1-3 + code:3E3-A8F-912+023-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 1-4 + code:3E3-A8F-912+033-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 1-5 + code:3E3-A8F-912+043-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 1-6 + code:3E3-A8F-912+053-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 2-1 + code:3E3-A8F-912+063-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 2-2 + code:3E3-A8F-912+073-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 2-3 + code:3E3-A8F-912+083-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 2-4 + code:3E3-A8F-912+093-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 2-5 + code:3E3-A8F-912+0A3-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 2-6 + code:3E3-A8F-912+0B3-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 3-1 + code:3E3-A8F-912+0C3-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 3-2 + code:3E3-A8F-912+0D3-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 3-3 + code:3E3-A8F-912+0E3-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 3-4 + code:3E3-A8F-912+0F3-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 3-5 + code:3E3-A8F-912+103-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 4-1 + code:3E3-A8F-912+113-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 4-2 + code:3E3-A8F-912+123-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 4-3 + code:3E3-A8F-912+133-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 4-4 + code:3E3-A8F-912+143-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 4-5 + code:3E3-A8F-912+153-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 4-6 + code:3E3-A8F-912+163-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 5-1 + code:3E3-A8F-912+173-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 5-2 + code:3E3-A8F-912+183-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 5-3 + code:3E3-A8F-912+193-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 5-4 + code:3E3-A8F-912+1A3-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 5-5 + code:3E3-A8F-912+1B3-A9F-E6A+E03-AAF-2A9 + cheat + description:Start on stage 5-6 + code:3E3-A8F-912+1C3-A9F-E6A+E03-AAF-2A9 + +cartridge sha256:17570ceec1b22153604622c4412d048dd8f7ccb4626daf9ddea96de8a062dbf2 + title:Castlevania II - Belmont's Revenge (USA, Europe) + cheat + description:Invincibility + code:EA5-86B-081 + cheat + description:Hit anywhere + code:009-36C-C4E + cheat + description:Multi-jump + code:872-94B-E62+C82-95B-E69+E62-96B-19E+102-97B-C41+202-98B-B39+152-99B-E67+C9D-47F-809 + +cartridge sha256:edb101e924f22149bdcbcfe6603801fdb4ec0139a40493d700fa0205f6dab30c + title:Castlevania Adventure, The (USA) + cheat + description:Infinite energy + code:00A-F28-3B7 + cheat + description:Infinite time - disable at end of stages + code:004-07F-3B7 + cheat + description:Infinite lives + code:006-94F-3B7 + cheat + description:Hit anywhere + code:002-61D-A22+002-71D-E62 + cheat + description:Multi-jump + code:007-E3E-80A+180-EBF-195+1A0-E8F-195+230-EAF-195+320-E7F-195+C90-ECF-195+CD0-E6F-195+CD0-E9F-195+E67-E2E-6E6 + cheat + description:Slightly improves speed - new games only + code:FF7-3CE-E69 + cheat + description:Don't lose weapon after being hit + code:00A-CF8-3B7 + cheat + description:Start with 5 lives + code:048-5EF-E62 + cheat + description:Start with 7 lives + code:068-5EF-E62 + cheat + description:Start with 2 energy bars + code:025-5CF-C42 + cheat + description:Start with 4 energy bars + code:045-5CF-C42 + cheat + description:Start with 6 energy bars + code:065-5CF-C42 + cheat + description:Start with timer at 2:15 for first stage + code:029-B3F-A26 + cheat + description:Start with timer at 4:15 for first stage + code:049-B3F-A26 + cheat + description:Start with timer at 7:15 for first stage + code:079-B3F-A26 + +cartridge sha256:56d3dee063b8801704a284bd1bc229b94f15a3a448f485d347f04283d9bd16d7 + title:Castlevania Legends (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:C97-3BA-C45 + cheat + description:Infinite lives + code:DA3-45B-4C1 + cheat + description:Infinite time + code:C9D-85D-6E2 + cheat + description:Disable death traps + code:C94-5CA-D5D + cheat + description:Fast walk left + code:11C-9DB-F7D + cheat + description:Fast walk right + code:11C-76B-F7D + cheat + description:Fast jump left + code:112-D6A-F7D + cheat + description:Fast jump right + code:112-B5A-F7D + cheat + description:Hit anywhere + code:4B3-49D-803+C94-5CA-D5D + cheat + description:Multi-jump + code:CD7-34A-F75+FA1-70A-4C1+037-33A-3B6+287-32A-081+517-36A-E62+557-2EA-80A+597-35A-191+677-31A-E69+C97-37A-C49+C9F-E4E-A29+CB7-30A-3B4 + +cartridge sha256:d8e44a2c2aa67f9afa49365f62802160842aef48d2003a69daeb109813f6f20c + title:Contra - The Alien Wars (USA) (SGB Enhanced) + cheat + description:Invincibility + code:3EB-81B-4CA + cheat + description:Infinite smart bombs + code:007-E2C-19E + cheat + description:Hit anywhere + code:003-77E-B3F+003-7CE-A2B+003-82E-C43+003-87E-F7F+003-C3E-3B2 + cheat + description:Get 5 smart bombs after you die + code:052-B1B-E6E + cheat + description:Get 9 smart bombs after you die + code:092-B1B-E6E + cheat + description:Don't flash after getting hit + code:010-6FB-7FB + cheat + description:Longer invincibility after getting hit + code:FF0-6FB-7FB + cheat + description:Start with Flame Thrower + code:017-97B-E6A + cheat + description:Start with Crush Gun + code:077-97B-E6A + cheat + description:Start with Homing shot + code:087-97B-E6A + cheat + description:Start with Spread shot + code:097-97B-E6A + +cartridge sha256:8e765a4e381462a29632b7a3c5421080be3e8445e5913d7e904a8e80d688ca81 + title:Contra (Japan) + cheat + description:Invincibility + code:BEB-3AC-191+BEA-A3C-191+BEA-0FE-191 + cheat + description:Hit anywhere + code:00A-D0C-91A+C3A-EAC-919+C6A-FBC-191 + cheat + description:Multi-jump + code:005-8CA-B3F+260-E6F-195+460-E9F-195+520-E7F-195+550-EAF-195+C90-EBF-195+CD0-E5F-195+CD0-E8F-195+E55-8BA-F73 + +cartridge sha256:d5a1c0e7af970859449c47fcc80a5f4dfa4f456b20fdfcd49e753ce46f2dc3da + title:Cyraid (USA) + cheat + description:Infinite lives + code:00D-8CB-E6E + cheat + description:1st nasty on bottom level of stage 1 is removed from the game + code:000-729-E6E + cheat + description:Collect only 1 energy capsule and all enemy robots are destroyed-can proceed to next room + code:AFA-4EE-19E + cheat + description:Skip to 3rd room after completing 1st + code:3EE-8AF-4CA+03E-8BF-F7E + cheat + description:Skip to 5rd room after completing 1st + code:3EE-8AF-4CA+05E-8BF-F7E + cheat + description:Skip to 8rd room after completing 1st + code:3EE-8AF-4CA+08E-8BF-F7E + cheat + description:Start with 4 lives + code:04E-7CE-F7E + cheat + description:Start with 6 lives + code:06E-7CE-F7E + cheat + description:Start with 9 lives + code:09E-7CE-F7E + +cartridge sha256:06d2f49483cf16f00580ba227d86174fdb9f72e555d9a9afea6aebcbfff012e4 + title:Daedalian Opus (USA) + cheat + description:Infinite time + code:00D-62D-3BA + cheat + description:Get password to select any level after completing level 1 + code:3E1-9AF-191+0A1-9BF-7FA + cheat + description:Start on level 5 or 6 after completing level 1 + code:3E1-9CF-2AA+051-9DF-F7E + +cartridge sha256:b482f9a96a292dea1fcc94bdeae24b664a3222c9eb820795388aab274eebdaf0 + title:Darkman (USA, Europe) + cheat + description:Infinite energy + code:BA5-0FF-081 + cheat + description:Infinite lives + code:014-DDF-E69 + cheat + description:Infinite time + code:005-97F-E6E + cheat + description:Start 1st life with mega-energy + code:63F-91C-91A + cheat + description:Start 1st life with 1/2 energy + code:0AF-91C-91A + cheat + description:Start rest of lives with mega-energy + code:636-40D-91A + cheat + description:Start with 9 minutes + code:909-ACA-E6B + cheat + description:Start with 1 life + code:002-4DF-E66 + cheat + description:Start with 8 lives + code:072-4DF-E66 + +cartridge sha256:122a1d3bd99c87a337f770fbdef2b7cf8538673df1595585af6684d4d4807614 + title:Darkwing Duck (USA) + cheat + description:Infinite lives + code:01A-0BF-C4D + cheat + description:Infinite ammo on pick-up + code:FAD-398-4C1 + cheat + description:Invincibility time lasts 4 seconds + code:AA0-64B-A2B + cheat + description:Invincibility time lasts 6 seconds + code:FF0-64B-A2B + cheat + description:1 touch by an enemy kills you + code:010-6FB-A2B + cheat + description:Start with 1 pt. of energy and 1 life - 1st game + code:011-84F-F7A + cheat + description:Start with 5 pts. of energy on 1st life and 5 lives - 1st game + code:051-84F-F7A + cheat + description:Start with 9 pts. of energy on 1st life and 9 lives - 1st game + code:091-84F-F7A + cheat + description:Start with 1 pt. of energy after 1st life + code:019-F0F-F7A + cheat + description:Start with 5 pts. of energy after 1st life + code:059-F0F-F7A + cheat + description:Start with 9 pts. of energy after 1st life + code:099-F0F-F7A + +cartridge sha256:61d632a2e17526cc55cc8e107abaf9aa11830cd4dd94c0b0f94d10a12a0c9f71 + title:David Crane's The Rescue of Princess Blobette (USA) + cheat + description:Infinite jellybeans + code:000-56D-E6E + cheat + description:Infinite lives + code:00D-4FD-3BE + cheat + description:Start with 2 honeys + code:02C-0E8-E66 + cheat + description:Start with 4 honeys + code:04C-0E8-E66 + cheat + description:Start with 8 honeys + code:08C-0E8-E66 + cheat + description:Start with 2 root beers + code:02C-0C8-E6A + cheat + description:Start with 4 root beers + code:04C-0C8-E6A + cheat + description:Start with 2 tangerines + code:02C-0A8-F72 + cheat + description:Start with 4 tangerines + code:04C-0A8-F72 + cheat + description:Start with 2 vanillas + code:02C-088-F7E + cheat + description:Start with 4 vanillas + code:04C-088-F7E + cheat + description:Start with 2 limes + code:02C-068-E6A + cheat + description:Start with 4 limes + code:04C-068-E6A + cheat + description:Start with 2 apples + code:02C-048-E6E + cheat + description:Start with 4 apples + code:04C-048-E6E + cheat + description:Start with 2 bananas + code:02C-028-E6A + cheat + description:Start with 4 bananas + code:04C-028-E6A + cheat + description:Start with 2 colas + code:02C-008-E6A + cheat + description:Start with 4 colas + code:04C-008-E6A + cheat + description:Start with 2 coconuts + code:02B-FE8-E66 + cheat + description:Start with 4 coconuts + code:04B-FE8-E66 + cheat + description:Start with 2 strawberries + code:02B-FC8-E6A + cheat + description:Start with 4 strawberries + code:04B-FC8-E6A + cheat + description:Start with 2 licorices + code:02B-FA8-E62 + cheat + description:Start with 4 licorices + code:04B-FA8-E62 + cheat + description:Start with 2 ketchups + code:02C-108-E6E + cheat + description:Start with 4 ketchups + code:04C-108-E6E + cheat + description:Start with 2 punches + code:02C-128-E6A + cheat + description:Start with 4 punches + code:04C-128-E6A + cheat + description:Start with 2 mints + code:02C-148-E6A + cheat + description:Start with 4 mints + code:04C-148-E6A + cheat + description:Start with 2 lives + code:02B-CA8-F7E + cheat + description:Start with 4 lives + code:04B-CA8-F7E + cheat + description:Start with 8 lives + code:08B-CA8-F7E + +cartridge sha256:1a62bbcaff8d12b752826472beac346e5fce9d8640f7ae23c6e390b79e55346d + title:Days of Thunder (USA, Europe) + cheat + description:Infinite time in pits + code:FAE-7B9-4C1 + cheat + description:Infinite fuel + code:002-948-2A3 + cheat + description:Car takes no damage + code:006-9CE-3B7 + cheat + description:Tires take no damage + code:C97-2FD-3BA + +cartridge sha256:d534102be843dc15a465709164e09e82c6bdf6df2ac440930af2e34c2f0e01ce + title:Dead Heat Scramble (USA) + cheat + description:Infinite time + code:004-05F-19E + cheat + description:Start on stage 2 + code:02B-0C8-E6E + cheat + description:Start on stage 3 + code:03B-0C8-E6E + cheat + description:Start on stage 4 + code:04B-0C8-E6E + cheat + description:Start on stage 5 + code:05B-0C8-E6E + cheat + description:Start on stage 6 + code:06B-0C8-E6E + cheat + description:Start on stage 7 + code:07B-0C8-E6E + cheat + description:Start on stage 8 + code:08B-0C8-E6E + cheat + description:Start on stage 9 + code:09B-0C8-E6E + cheat + description:Start on stage 10 + code:0AB-0C8-E6E + +cartridge sha256:2d8fb80ece07198260fb47b6a2e8d0097e2d6ca27fb21bc3c439f90d7880317d + title:Dig Dug (USA) + cheat + description:Infinite lives + code:008-1BB-19E + cheat + description:When Pookas are partially inflated, they don't shrink + code:004-50C-3BE + cheat + description:1 pump kills monster instantly + code:046-D9C-E6E+043-9ED-E6E+047-8EB-E6E + cheat + description:Start with 6 lives + code:06B-ACA-E66 + cheat + description:Start with 9 lives + code:09B-ACA-E66 + cheat + description:Start with 2 lives + code:02B-ACA-E66 + cheat + description:Start on level 4 (display still says level 1) + code:3EC-D9A-08A+04C-DAA-E62 + cheat + description:Start on level 2 (display still says level 1) + code:3EC-D9A-08A+02C-DAA-E62 + cheat + description:Start on level 9 (display still says level 1) + code:3EC-D9A-O8A+09C-DAA-E62 + +cartridge sha256:2781f6b1014336e3318073f162cadd970329c8148fc62b5e795441cd6fd57051 + title:Donkey Kong (World) (SGB Enhanced) + cheat + description:Infinite lives + code:009-4DF-3BE + cheat + description:Infinite time + code:00C-34F-E6E + cheat + description:Timer is 2x faster + code:02C-34F-E6E + cheat + description:Practice stage XX - level indicator doesn't work, can't go on to next level + code:3E4-F3D-081+XX4-F4D-4CE+004-F5D-C49 + cheat + description:Start with 36 lives + code:882-64F-F7A + +cartridge sha256:b490c89efe718633b07381def66ce0ed58a5075aabe40c6e644baf2b408a76f4 + title:Donkey Kong (World) (Rev A) (SGB Enhanced) + cheat + description:Invincibility + code:C93-B4A-3B2+C94-4DA-2A3+C95-46A-3B2 + cheat + description:Invincibility (alt) + code:FA1-F5A-E61 + +cartridge sha256:eaf831ddd75e7cbc9990e478a139ac162034c03377670fdb79615a9aa2cc570d + title:Donkey Kong Land (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:3E0-81B-4CA + cheat + description:Infinite lives + code:00D-9DB-3BE+21D-A0B-E61 + cheat + description:Multi-jump + code:CD5-AFA-081+F65-B4A-2AA+005-B5A-D5E+015-AAA-D5A+1F5-ACA-B36+295-B1A-F71+2D5-B2A-191+305-ADA-08A+365-B3A-F72+BD5-B0A-C46+CA5-ABA-F71 + cheat + description:Always save game at end of level, regardless if you have KONG letters or not + code:C30-CBB-C41 + cheat + description:Lose all your lives when you die + code:C3D-A0B-E61 + cheat + description:If you get hit you don't change characters until you are back at the map screen + code:C9D-FDB-4C1 + cheat + description:Each banana gives you mega lives (disable when you have enough lives) + code:004-C6B-3BE+3E4-C0B-3B2 + cheat + description:Change soundtrack + code:002-1FB-3BE + cheat + description:Start with 1 life + code:00E-899-F7E+00E-958-F7E + cheat + description:Start with 9 lives + code:08E-899-F7E+08E-958-F7E + cheat + description:Start with 15 lives + code:0EE-899-F7E+0EE-958-F7E + cheat + description:Start with 99 lives + code:63E-899-F7E+63E-958-F7E + +cartridge sha256:75f902ab8674c3cd379438fbd54cfe7e87ca3ddf9727679547261d1b77db720b + title:Double Dragon (USA, Europe) + cheat + description:Infinite health + code:012F98C4 + cheat + description:Infinite lives + code:010499C4 + +cartridge sha256:ba60449b8e57d1288e78a2cb69c6df46e1443cc611d139d27f4c5d5fad307fd3 + title:Double Dragon 3 (USA, Europe) + cheat + description:Infinite lives + code:000-0E8-19E + cheat + description:Infinite coins + code:00F-1BF-E6E + cheat + description:Start with 4 lives + code:030-9FF-F72 + cheat + description:Start with 10 lives + code:090-9FF-F72 + cheat + description:Start with 13 lives + code:0C0-9FF-F72 + cheat + description:Start with 5 coins + code:049-498-E6E + cheat + description:Start with 10 coins + code:099-498-E6E + cheat + description:Start with 20 coins + code:199-498-E6E + cheat + description:Start 1st life with 5 energy points + code:500-97F-194 + cheat + description:Start 1st life with 15 energy points + code:F00-97F-194 + cheat + description:Start with 5 points of energy - after 1st life + code:500-138-194 + cheat + description:Start with 15 points of energy - after 1st life + code:F00-138-194 + +cartridge sha256:936df4d0f74620c784129259a22fc3216eea04f70c10cab6005457a0f681e313 + title:Double Dribble - 5 on 5 (USA) + cheat + description:Infinite time + code:00B-8CF-E6E + cheat + description:No computer scoring + code:00D-64F-6E2 + cheat + description:Game lasts only 1 quarter, goes straight to 4th quarter + code:04C-E2F-E6E + cheat + description:When selecting skill level, keep pressing down. Bleeping will continue, and computer will become more and more skillful. + code:FFA-0BE-E66 + +cartridge sha256:34f11935cb3c23102462aab9d96c09e25b81b35eef91f5e5456b2c3665734f0e + title:Dragon Warrior III (USA) + cheat + description:Enemies only attack themselves + code:04A-DDA-B3A+F6A-DCA-4CA + cheat + description:HP set to approx 198 every move + code:7CF-5EA-08F + +cartridge sha256:64d791cadae2500ddd7dfd3ebedc48a182fdc0e027f9bfd74c8ff65b56371dbf + title:Druaga no Tou (Japan) + cheat + description:Reset to see ending + code:081-6FF + +cartridge sha256:9eee3454a1198c01c7adb9562507f2eb5791888c63885bea2e933948f66f6321 + title:Extra Bases! (USA) + cheat + description:Outs aren't counted + code:000-0BE-3BA + cheat + description:Strikes aren't counted + code:000-7AB-3BA + cheat + description:Balls aren't counted + code:000-8BB-3BA + cheat + description:Opponents can't score (disable when you're batting so you can score) + code:00B-91A-19A + cheat + description:One strike and you're out + code:01F-D6F-E66 + cheat + description:2 strikes and you're out + code:02F-D6F-E66 + cheat + description:1 out and side is retired + code:01F-F0F-E66 + cheat + description:2 outs and side is retired + code:02F-F0F-E66 + cheat + description:1 ball and you walk + code:01F-C0F-F7A + cheat + description:2 balls and you walk + code:02F-C0F-F7A + +cartridge sha256:571e45610cae528b3c50304c42c946f307d71797fc2029e9ca1978045dd5186d + title:F-15 Strike Eagle (USA, Europe) + cheat + description:Infinite bullets + code:FAA-52D-4C1 + cheat + description:Infinite sidewinders + code:FA8-EEF-4C1 + cheat + description:Infinite mavericks + code:FA8-ABF-4C1 + cheat + description:Infinite E.C.M. + code:FA8-5BF-4C1 + cheat + description:Fly very slowly + code:013-BCC-E62 + cheat + description:Fly at supersonic speed + code:093-BCC-E62 + cheat + description:Start with 10 sidewinders + code:0A3-88C-912 + cheat + description:Start with 50 sidewinders + code:323-88C-912 + cheat + description:Start with 90 sidewinders + code:5A3-88C-912 + cheat + description:Start with 10 mavericks + code:0A3-8DC-D56 + cheat + description:Start with 50 mavericks + code:323-8DC-D56 + cheat + description:Start with 90 mavericks + code:5A3-8DC-D56 + cheat + description:Start with 10 E.C.M. + code:0A3-92C-80A + cheat + description:Start with 50 E.C.M. + code:323-92C-80A + cheat + description:Start with 90 E.C.M. + code:5A3-92C-80A + cheat + description:Start with 513 bullets + code:023-9BC-E66+013-9AC-6EA + cheat + description:Start with 2049 bullets + code:083-9BC-E66+013-9AC-6EA + cheat + description:Start with 4097 bullets + code:103-9BC-E66+013-9AC-6EA + +cartridge sha256:db506cb639b6336bf17c993c597da3990398ec01e235e0d9236e9df87ab0439e + title:Ferrari Grand Prix Challenge (USA, Europe) + cheat + description:Don't lose speed when touching side of track in qualifying round or race. Hitting sign will slow you down (if you accelerate fully, release A and position car in middle of track, it will steer itself). + code:004-58C-19E + cheat + description:When you crash with another car, your speed won't drop to 0 + code:000-22C-C49 + cheat + description:No qualifying timer + code:00A-39B-E6E+00A-1AB-E6E + +cartridge sha256:9b72e7d44d1cb31a06cf4e630c83abc61fb7218e3d55d7dc6aa1ecbf9e490cf0 + title:Fighting Simulator 2 in 1 (USA, Europe) + cheat + description:Infinite energy + code:3D7-3CE-19A + cheat + description:Infinite lives + code:008-D7E-19E + cheat + description:Start with 5 lives + code:057-24E-E66 + cheat + description:Start with 9 lives + code:097-24E-E66 + cheat + description:Start with 15 lives + code:0F7-24E-E66 + +cartridge sha256:5a462f1bbb4e75823c04c7a0b2a7497cbe7e709a425854c71c1fc4d60f16f445 + title:Final Fantasy Adventure (USA) + cheat + description:Most items are free + code:406-06A-E6E + cheat + description:Start with 255 of each ability + code:FFE-6B9-E62 + cheat + description:Start with 65,330 GP + code:FFE-CC9 + +cartridge sha256:e5b1d116a8fb01b7a7213f906b3ef1bcc91a18f6826b01ee1bccd89429a0d906 + title:Final Fantasy Legend, The (USA) + cheat + description:Human male - Start with 1 strength point + code:011-238-C4A + cheat + description:Human male - 5 strength points + code:051-238-C4A + cheat + description:Human male - 2 defense points + code:021-248-E6E + cheat + description:Human male - 6 defense points + code:061-248-E6E + cheat + description:Human male - 3 agility points + code:031-258-F7A + cheat + description:Human male - 7 agility points + code:071-258-F7A + cheat + description:Human male - 4 mana points + code:041-268-E6A + cheat + description:Human male - 8 mana points + code:081-268-E6A + cheat + description:Human male - 1 HP + code:012-588-19A + cheat + description:Human male - Start with 5 HP + code:052-588-19A + +cartridge sha256:2d89231f9e264a024d634bcf7d00de5a66d8a45f6f4ca33e1fc1602a35b9840b + title:Final Fantasy Legend II (USA) + cheat + description:Infinite HP (don't heal or stay and Inn) + code:B90-64B-A9E + cheat + description:Get extra GP and Meat + code:C9D-23B-2AA + cheat + description:Get tons of GP after every battle + code:00D-23B-21A + cheat + description:Engage in a fight every second + code:37F-C5D-36E + cheat + description:All characters start with 15,163 HP (shows only 999) + code:005-96F-08B+005-9CF-08B + cheat + description:Start with 9 HP + code:098-E28-086 + cheat + description:Start with 9 defense points + code:098-E68-E66 + cheat + description:Start with 9 mana points + code:098-E78-E66 + cheat + description:Start with 9 agility points + code:098-E58-F7E + cheat + description:Start with 9 strength points + code:098-E48-F72 + cheat + description:Start with 9 swords (if your character can start with swords) + code:09E-818-2A2 + +cartridge sha256:5ed87f65225b72a74c3c04a4e5d67683fb5cc33e5f1266157350828ab973fc1d + title:Final Fantasy Legend III (USA) + cheat + description:Set initial power to mega-power + code:FFA-928-E6A+FF8-918-2A2+FF8-938-2A2 + cheat + description:Always strike first + code:FFA-A09-343 + cheat + description:Able to run from every battle, even bosses + code:FFA-B4B-AA3 + cheat + description:Gain extra EXP and GP + code:D77-CAA-356 + cheat + description:Defeating leftmost or upper-left enemy defeats all enemies on screen + code:024-CAA-356 + cheat + description:Gain a level after every battle on a new game - Character 1 (Hero - Arthur) + code:FFA-878-E6E + cheat + description:Gain a level after every battle on a new game - Character 2 (Boy - Curtis) + code:FFA-E78-E6E + cheat + description:Gain a level after every battle on a new game - Character 3 (Girl - Gloria) + code:FFB-478-E6A + cheat + description:Gain a level after every battle on a new game - Character 4 (Heroine - Sharon) + code:FFB-A78-E6A + +cartridge sha256:8327ed0d686d223995f86c267eeaf5f450c0d16a9bf9b6925dcb52cd1481f0e1 + title:Fish Dude (USA) + cheat + description:Infinite lives + code:002-A8F-3BE + cheat + description:No timer + code:215-25F-081 + cheat + description:Start with 1 life + code:002-3DF-E62 + cheat + description:Start with 5 lives + code:042-3DF-E62 + cheat + description:Start with 9 lives + code:082-3DF-E62 + cheat + description:Start with 15 lives (ignore counter for first 5 lives) + code:0E2-3DF-E62 + +cartridge sha256:da62ce2133b788e88605fad8f8d15582457d2a08de88124f231ef943ffba8805 + title:Fist of the North Star (USA) + cheat + description:Almost invincible + code:21E-9FF-4C1 + cheat + description:No energy loss from weapons thrown + code:21F-A5F-4C1 + cheat + description:Start on level 5 + code:05B-CCE-E6E + cheat + description:Start on level 9 + code:09B-CCE-E6E + cheat + description:Start with 25% energy + code:40F-F7E-195 + cheat + description:Start with 50% energy + code:7F4-F7E-195 + cheat + description:Start with 75% energy + code:C44-F7E-195 + +cartridge sha256:eededd0318cc5b80a2aa019a9a7eb3dfb9cb9ac11d974d24d704d7d4cf771a94 + title:Flash, The (USA, Europe) + cheat + description:Infinite energy (except against exploding bombs) + code:00A-85F-E6D + cheat + description:Infinite lives + code:003-A8F-E69 + cheat + description:Infinite time (disable at end of each stage) + code:00D-B6C-3BE + cheat + description:Start with 1 life + code:015-9CF-E66 + cheat + description:Start with 6 lives + code:065-9CF-E66 + cheat + description:Start with 1/2 surge power + code:4C5-A1F-D54 + cheat + description:Start with 1/2 energy + code:245-A6F-C4B + +cartridge sha256:44bd5dd98b6ca3730435197d5af7f4fb6fa0f86fecf9b74005d5a76c28870f88 + title:Foreman for Real (USA, Europe) + cheat + description:Enable everyone for tournament mode + code:00C-9BF-E6E+13C-A0F-D56 + +cartridge sha256:af4fda51b28e426f6cab8b48037cf2cbc18ad6c1f02311ad901365aa52c918b7 + title:Ganso!! Yancha Maru (Japan) + cheat + description:Invincibility (the second code kills enemies on contact) + code:007-76B-F76+007-7BB-E6E + cheat + description:Infinite Shurikens on pick-up + code:01B-8DF-E66 + cheat + description:999 coins on pick-up + code:00C-5FF-A29 + cheat + description:Infinite time + code:00B-B9F-3B7 + +cartridge sha256:78d35816612a521315e0b0618886e4b9e1005c58e459248c7e7585d8c04e71ac + title:George Foreman's KO Boxing (USA, Europe) + cheat + description:Infinite health (display still decreases) + code:3E9-CBE-4CA + cheat + description:Infinite time + code:001-89E-E6E + cheat + description:Infinite super punch + code:3E7-EEE-08A + +cartridge sha256:dc898d66af6c2ada73946f1cb68f1539c16240060f72e31da5bee2ba2655fcbc + title:Goal! (USA) + cheat + description:Infinite time + code:009-EFE-E6E + cheat + description:Select time of up to 99 minutes per half + code:633-ECB-5DE + cheat + description:No goals scored against you by computer + code:00A-DAB-19A + cheat + description:Some teammates have a mega-kick + code:225-5BA-C46 + cheat + description:Player 2 is fastest on the pitch + code:FF5-5AA-CDE+FF5-5BA-C46+FF5-5CA-CBE + +cartridge sha256:185f092bbebd5fa29a82ffb7d18c8242f75d6f8fee968cf6dee00b32a879febb + title:God Medicine - Hukkoku Ban (Japan) (SGB Enhanced) + cheat + description:Sell an item to get maximum cash + code:00F-60A-E66 + cheat + description:Gain maximum EXP after each battle + code:006-0CB-809 + cheat + description:No random battles + code:C92-94C-C49 + cheat + description:Enemies have no HP + code:AF0-4AB-802+AF0-52B-802 + cheat + description:Final boss has no HP + code:005-D68-E66 + +cartridge sha256:896d9ffbdfe35c802cdcb66b5a6ce84a4ad6bc356c85067904883944a621cbb4 + title:Golf (World) + cheat + description:Wind power is 10 mph + code:3ED-87E-08A+5ED-88E-C4E + +cartridge sha256:2ed249eb86d4fd01e10efd1787a545f4921c19dc0e00b5c516b8bbdfe4c4aedc + title:Gradius - The Interstellar Assault (USA) + cheat + description:Invincibility + code:C91-18A-081 + +cartridge sha256:bfbed25beef74dec194a7330e3f4864a4b82f28927121cf03d9b871965553420 + title:Heavyweight Championship Boxing (USA) + cheat + description:No ring timer + code:00B-A4E-E6E + cheat + description:No round increase + code:AF6-E1B-19E + cheat + description:Juggle your power - can alter power settings and give full power in all categories + code:008-B2E-19E + cheat + description:Start with punch, life and speed at 1 + code:014-78F-E66 + cheat + description:Start with punch, life and speed at 2 + code:024-78F-E66 + cheat + description:Start with punch, life and speed at 3 + code:034-78F-E66 + cheat + description:Start with punch, life and speed at 4 + code:044-78F-E66 + cheat + description:Start with punch, life and speed at 5 + code:054-78F-E66 + cheat + description:Start with punch, life and speed at 6 + code:064-78F-E66 + cheat + description:Start with punch, life and speed at 7 + code:074-78F-E66 + cheat + description:Start with punch, life and speed at 8 + code:084-78F-E66 + cheat + description:Start with punch, life and speed at 9 + code:094-78F-E66 + cheat + description:Start with super power + code:994-78F-E66 + +cartridge sha256:6bf16580b0047f7b0dbaf2bf9a2d34095e057efe70414feeda48de8dcf8952fd + title:High Stakes (USA) + cheat + description:Once you've collected an item from Shady, you can't lose it - blackjack mission 1 only + code:00C-ADB-3BE+006-6BA-3BE + cheat + description:Betting and cheat tokens cost 0 + code:00B-B1E-A22 + cheat + description:No limit to how much you can buy of each item from Shady + code:3E0-BOB-081+000-B2B-E61 + cheat + description:Start with 1/2 money (display will show $50,000) + code:628-D8F-E65 + cheat + description:Start with over $65,000 (display will show $50,000) + code:FF8-D8F-E65 + +cartridge sha256:f6bdf9f2c4148ce7da23986524781ee844729f360ff9ef27d695ecf0886ff9e0 + title:Hit the Ice (USA, Europe) + cheat + description:Infinite timer + code:00A-54E-E6E + cheat + description:Faster timer + code:02A-54E-E6E + cheat + description:Infinite super shots + code:002-97D-3BA + cheat + description:Only 1 super shot allowed + code:012-99D-C42 + cheat + description:5 super shots allowed + code:052-99D-C42 + cheat + description:10 super shots allowed + code:0A2-99D-C42 + cheat + description:1-minute periods - vs. mode + code:011-F6B-F7E + cheat + description:2-minute periods - vs. mode + code:021-F6B-F7E + cheat + description:10-minute periods - vs. mode + code:0A1-F6B-F7E + cheat + description:Neither team can score + code:1004-39B-E6E + cheat + description:10 seconds in short race after the first shot of 20 seconds + code:0A1-97E-6EA + cheat + description:15 seconds in short race after the first shot of 20 seconds + code:0F1-97E-6EA + cheat + description:5 seconds in short race after the first shot of 20 seconds + code:051-97E-6EA + +cartridge sha256:2449307e540566135734977b01ca488a3feb2ce9d887f69a275a308b5a78cc3f + title:Home Alone (USA, Europe) + cheat + description:Infinite hit points + code:00B-5AD-19E + cheat + description:No enemies + code:214-34F-081 + cheat + description:Need 1 treasure to finish level 1 + code:013-E5D-7FA + cheat + description:Start with 1 hit point + code:013-ADD-E66 + cheat + description:Start with 6 hit points + code:063-ADD-E66 + cheat + description:Start with 9 hit points + code:093-ADD-E66 + +cartridge sha256:f1506c97b36e776a8839187b278efacdfacaa6bb5cf0b3f18e04ced31d0d4a01 + title:Home Alone 2 - Lost In New York (USA, Europe) + cheat + description:Infinite lives + code:007-82E-19E + cheat + description:Infinite hits unless picked up by shoulders + code:007-E9E-19E + cheat + description:Get 111,111 points instantly + code:006-75E-08B + cheat + description:Start with 5 lives + code:056-6FE-E66 + cheat + description:Start with 6 lives + code:066-6FE-E66 + +cartridge sha256:0dc2278500feb3844ba0ceabee289be011da1084903ab1c3fd681c83e7191118 + title:Hook (USA) + cheat + description:Infinite lives + code:3DC-FDD-3BE + +cartridge sha256:a04db245f19a55cd3ff43e2b3fc51cc747fc048a551c4e18639fef4af77553e1 + title:Humans, The (USA) + cheat + description:Infinite humans + code:FA3-E9F-4C1 + cheat + description:Infinite time + code:FA9-B7C-4C1 + cheat + description:Start with 6 humans + code:06D-609-D5A + cheat + description:Start with 9 humans + code:09D-609-D5A + cheat + description:Start with 15 humans + code:0FD-609-D5A + +cartridge sha256:ef563c4a4b063ea045d71b435dd078c19d0738f85079928803167cee8f34a4ec + title:Incredible Crash Dummies, The (USA, Europe) + cheat + description:Infinite time + code:001-3EC-E6E + cheat + description:Faster timer + code:021-3E6-E6E + cheat + description:Don't lose money when you go through fire + code:00B-00A-195 + cheat + description:More cash for each hit + code:851-49C-E64 + cheat + description:Start with 2 lives + code:022-A9F-F7E + cheat + description:Start with 4 lives + code:042-A9F-F7E + cheat + description:Start with 8 lives + code:082-A9F-F7E + +cartridge sha256:a900ffcc69fa1fa94dc99584b94914de46d2fa9f1a38c8c303c493a5ee008fec + title:In Your Face (USA) + cheat + description:Computer can't score - when it scores, you get the points + code:004-E9E-6E6 + cheat + description:Opponents are frozen - 2-on-2 game + code:C38-AAF-E61 + cheat + description:5-second game + code:05A-08E-80F + cheat + description:10-second game + code:0AA-08E-80F + cheat + description:20-second game + code:20A-08E-80F + +cartridge sha256:616202e0c2bea4898268c9b3a4eb22e198f1b559e29406057e039dded3db9637 + title:Jeep Jamboree (USA) + cheat + description:Always finish in 1st place + code:3EC-62E-E68+01C-63E-19A + cheat + description:Mega speed - stay at constant high speed even when off course and hitting rocks + code:799-D49-19F+799-D79-19B + cheat + description:Race 1 lap shorter + code:02B-F0A-E6E + cheat + description:Race 2 laps shorter + code:03B-F0A-E6E + cheat + description:Race 3 laps shorter + code:04B-F0A-E6E + +cartridge sha256:873d813fc51b735571c721c12922e85f200ee66f0cb742a60e4a9a63aea74944 + title:Jetsons, The - Robot Panic (USA, Europe) + cheat + description:Infinite lives + code:00F-C7F-E6E + cheat + description:Infinite energy - some robots can't be killed (disable to fight them) + code:009-088-3B7 + cheat + description:Max collectible energy + code:09F-1EC-F7E + cheat + description:Capped robots on first Elroy stage take 1 hit to kill + code:012-A7B-E62 + cheat + description:Capped robots on first Elroy stage take 8 hits to kill + code:082-A7B-E62 + cheat + description:Start with 4 lives + code:04F-16C-E66 + cheat + description:Start with 7 lives + code:07F-16C-E66 + cheat + description:Start with 9 lives + code:09F-16C-E66 + +cartridge sha256:bbc006dcf175f1fec822c533bed6abc136a98bcb3b6f8d726cc87c8e17c62e1f + title:Joe & Mac (USA) + cheat + description:Infinite lives + code:002-37D-E6E + cheat + description:Infinite energy + code:FAB-E9C-4C1 + cheat + description:Take one hit and lose life + code:AFB-E8C-A2C + cheat + description:No extra energy from pick-ups + code:00B-D8C-3B7 + cheat + description:Start with 1 life + code:01A-81F-E66 + cheat + description:Start with 6 lives + code:06A-81F-E66 + cheat + description:Start with 9 lives + code:09A-81F-E66 + cheat + description:Start on level 3 + code:3EA-89F-6E9+02A-8AF-7FD+E0A-8BF-2A9 + cheat + description:Start on level 6 + code:3EA-89F-6E9+05A-8AF-7FD+E0A-8BF-2A9 + cheat + description:Start on level 9 + code:3EA-89F-6E9+08A-8AF-7FD+E0A-8BF-2A9 + +cartridge sha256:63a7bfef616b1f9c19c90fdbbea1a096fd1ab6aad16f67d619b07842b0ad04c1 + title:Jordan vs Bird - One on One (USA, Europe) + cheat + description:Infinite time of possession-1-on-1 game + code:007-06D-E6E + cheat + description:8 seconds of possession-1-on-1 game + code:08D-D67-7FA + cheat + description:10 seconds of possession-1-on-1 game + code:0AD-E67-7FA + cheat + description:15 seconds of possession-1-on-1 game + code:0FD-D67-7FA + cheat + description:No timer + code:007-48D-E6E + cheat + description:5 points on 3-point shots + code:056-72D-E62+056-81D-E62 + cheat + description:8 points on 3-point shots + code:086-72D-E62+086-81D-E62 + cheat + description:12 points on 3-point shots + code:0C6-72D-E62+0C6-81D-E62 + cheat + description:5 points on 2-point shots + code:056-A1D-E6E+056-ADD-E62 + cheat + description:8 points on 2-point shots + code:086-A1D-E6E+086-ADD-E62 + cheat + description:12 points on 2-point shots + code:0C6-A1D-E6E+0C6-ADD-E62 + +cartridge sha256:6b13a664a3c74e6e61b019f4024f65b3fb301ee5518a9cf9e2a27dc41bbdd561 + title:Jurassic Park (USA) + cheat + description:Infinite hearts + code:00C-46E-19E + cheat + description:Infinite lives + code:00C-11E-E6E + cheat + description:Remove All Objects (Disable this code to collect eggs, enable it to avoid the dinosaurs) + code:9BC-55B-10A+F80-75C-CEF+006-42B-DF0 + cheat + description:Only need 1 card to open the gate + code:AF3-C9B-7F6 + cheat + description:Canï¾’t collect any energy + code:003-DCB-19A + cheat + description:First Aid gives you mega energy + code:AF3-DCB-19A + cheat + description:Get max energy from collecting energy + code:3E3-DAB-4CA+033-DBB-F7E + cheat + description:Die after one hit + code:AFC-46E-19E + cheat + description:Start with 1 lives + code:013-9EF-E66 + cheat + description:Start with 5 lives + code:053-9EF-E66 + cheat + description:Start with 7 lives + code:073-9EF-E66 + cheat + description:Start with 9 lives + code:093-9EF-E66 + cheat + description:Start with 1 heart - after 1st life + code:01C-06E-F7A + cheat + description:Start with 9 hearts - after 1st life + code:09C-06E-F7A + cheat + description:Start with 1 heart - 1st life + code:013-9BF-F7A + cheat + description:Start with 9 hearts - 1st life + code:093-9BF-F7A + +cartridge sha256:b0a1019b6199c923a6a764c15e7bf6d1bb0bef8a042c383f3e3ead74ab171ede + title:Kid Dracula (USA, Europe) + cheat + description:Invincibility + code:008-13F-367 + cheat + description:Infinite lives + code:FAB-F5A-4C1 + cheat + description:Start with 1 energy heart + code:015-43F-E66 + cheat + description:Start with 5 energy hearts + code:055-43F-E66 + cheat + description:Start with 1 life + code:005-4BF-E62 + cheat + description:Start with 5 lives + code:045-4BF-E62 + cheat + description:Start with 10 lives + code:095-4BF-E62 + cheat + description:Start on level 3 + code:030-CD8-E6E + cheat + description:Start on level 5 + code:050-CD8-E6E + +cartridge sha256:92c1fbf422abb8f09ca7fdbb563d1284108cc042e60e1222422986d9a59f9d97 + title:Kid Icarus - Of Myths and Monsters (USA, Europe) + cheat + description:Collected hammers seem to count towards your enemy kill number + code:C9A-D18-08F+7AA-B48-E69 + cheat + description:Maximum kills after killing first enemy + code:00C-CAF-A29 + +cartridge sha256:4a091956a579de541aa2eef831e6d0c07d8324255cff7cc889c8ed9b70847769 + title:Killer Instinct (USA, Europe) (SGB Enhanced) + cheat + description:Infinite health + code:FA7-B0B-4C1 + cheat + description:Infinite time + code:002-199-19E + cheat + description:Round starts with 10 seconds + code:103-1CD-80C + cheat + description:Round starts with 30 seconds + code:303-1CD-80C + cheat + description:Round starts with 50 seconds + code:503-1CD-80C + cheat + description:Round starts with 75 seconds + code:753-1CD-80C + cheat + description:Fierce tiger fury does no damage + code:00B-428-6E2 + cheat + description:Fierce tiger fury does more damage + code:88B-428-6E2 + cheat + description:Fierce tiger fury kills + code:FFB-428-6E2 + cheat + description:Fierce wind kick does no damage + code:00B-698-916 + cheat + description:Fierce wind kick does more damage + code:88B-698-916 + cheat + description:Fierce wind kick kills + code:FFB-698-916 + cheat + description:Fierce laser blade does no damage + code:00B-838-91E + cheat + description:Fierce laser blade does more damage + code:88B-838-91E + cheat + description:Fierce laser blade kills + code:FFB-838-91E + cheat + description:Freeze everything except timer + code:D90-38D-B8A + cheat + description:Start with very little energy + code:012-EAD-919 + cheat + description:Start with 1/4 energy + code:4B2-EAD-919 + cheat + description:Start with 1/2 energy + code:882-EAD-919 + cheat + description:Start with 3/4 energy + code:B42-EAD-919 + +cartridge sha256:0f6dba94fae248d419083001c42c02a78be6bd3dff679c895517559e72c98d58 + title:Kirby's Dream Land (USA, Europe) + cheat + description:Infinite lives + code:FA6-DBB-4C1 + cheat + description:Infinite lives and gain points when hit + code:CA1-DOC-FAB+B1F-F1D-649 + cheat + description:Infinite vitality bars except against end of stage boss + code:FA4-63B-4C1 + cheat + description:Start with 2 lives + code:021-BBF-F7E + cheat + description:Start with 5 lives + code:051-BBF-F7E + cheat + description:Start with 9 lives + code:091-BBF-F7E + cheat + description:Start with 2 vitality bars + code:021-C0F-F72 + cheat + description:Start with 5 vitality bars + code:051-C0F-F72 + cheat + description:Start with 9 vitality bars + code:091-C0F-F72 + +cartridge sha256:08ddc36709d551b6c2b768e8280e0213ebe89a5088b34e1cc6c0e14977b8e312 + title:Kirby's Dream Land 2 (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility after one hit + code:003-838-19E + cheat + description:Don't flash at all after getting hit + code:012-BFA-6EB + cheat + description:Don't flash as long after getting hit + code:202-BFA-6EB + cheat + description:Infinite energy + code:FA7-CBD-4C1 + cheat + description:Infinite lives + code:FA1-C4B-4C1 + cheat + description:One hit and you die + code:AFA-9EC-A28 + cheat + description:Each star worth an extra life + code:01C-DE8-F76 + cheat + description:Can't get extra lives from stars + code:00C-DC8-19A + cheat + description:Each star takes away a life + code:01C-DE8-F76+3DC-878-19A + cheat + description:Start with 1 life + code:00D-589-E62 + cheat + description:Start with 5 lives + code:04D-589-E62 + cheat + description:Start with 7 lives + code:06D-589-E62 + cheat + description:Start with 10 lives + code:09D-589-E62 + +cartridge sha256:43bbc3111fe66b5d87940da810a1a0839ab7d48b50c327807538026241b40295 + title:Kirby's Pinball Land (USA, Europe) + cheat + description:Infinite bonus room time - disable to exit + code:FAF-1AA-4C1 + cheat + description:Infinite balls + code:005-34B-E69 + cheat + description:Infinite M-Tomato + code:743-F6B-C49 + cheat + description:30 seconds allowed in Wispy-Woods bonus room + code:300-B99-6EB + cheat + description:99 seconds allowed in Wispy-Woods bonus room + code:990-B99-6EB + cheat + description:Go straight to end of level bosses + code:3EE-CF9-2A9+01E-D09-A21 + cheat + description:Go straight to bonus games + code:3EE-CF9-2A9+02E-D09-A21 + cheat + description:DeDeDe takes 1 hit + code:01D-1DB-B36 + cheat + description:Start with 5 balls + code:054-7CF-E66 + cheat + description:Start with 1 ball + code:014-7CF-E66 + cheat + description:Start with 9 balls + code:094-7CF-E66 + +cartridge sha256:cca2e1e06b50869a16b0b7bcef0095ff7d53af926419808da2b82fbab3762750 + title:Krusty's Fun House (USA, Europe) + cheat + description:Infinite lives + code:FA3-ACF-4C1 + cheat + description:Infinite pies + code:FA6-EBB-4C1 + cheat + description:Start with 2 pies + code:022-5DF-C42 + cheat + description:Start with 7 pies + code:072-5DF-C42 + cheat + description:Start with 15 pies (only shows 10) + code:0F2-5DF-C42 + cheat + description:Start with 2 lives + code:022-43F-E66+022-58F-E66 + cheat + description:Start with 6 lives + code:062-43F-E66+062-58F-E66 + cheat + description:Start with 9 lives + code:092-43F-E66+092-58F-E66 + +cartridge sha256:dff23b973c6c5e85da109dfb346ee396625fa7f934bc7c4b853ce4f237dfa42a + title:Kung-Fu Master (USA, Europe) + cheat + description:Mostly invincible + code:009-FFF-3BE+00A-42F-A28 + cheat + description:Freeze timer (disable to complete level) + code:00C-8EA-3BE + cheat + description:Touch weak enemies to defeat them + code:009-E6F-F72 + +cartridge sha256:dbcecd9ed9ee70e8f3a231eb0bda95c882ff0e9697d52fe919a02f076962de91 + title:Lamborghini American Challenge (USA, Europe) + cheat + description:Infinite money + code:002-8AC-910 + cheat + description:Infinite turbos + code:009-318-3BE + cheat + description:Increased money + code:99D-1AE-E6A + cheat + description:No Loss Of Speed On Collisions + code:001-C39-6EB + cheat + description:No Loss Of Speed When Off Track + code:00A-189-F7A + cheat + description:Start With 2 Turbos + code:01D-27E-E6E + cheat + description:Start With 6 Turbos + code:05D-27E-E6E + cheat + description:Start With 10 Turbos + code:09D-27E-E6E + +cartridge sha256:2451d61085652f25d36e35f1fa50dc7e6b51c6e20a50120decc33efcf1c91109 + title:Last Action Hero (USA, Europe) + cheat + description:Level select (# = level 1-9 or A for ending credits) + code:0#1-88F-E6E + +cartridge sha256:21f712e213f43f9efb93ca039a5190fc09325d5d932af1fb2f8e90b4f9fd169f + title:Legend of Zelda, The - Link's Awakening (USA, Europe) + cheat + description:Infinite health + code:FAO-999-4C1 + cheat + description:Infinite rupees (rupees aren't deducted for purchases you can afford) + code:FAF-BDA-4C1+FAF-B2A-4C1 + cheat + description:All items you get start at max power. When you get an item, you must have a space open (either A or B). + code:09C-56B-E6E+09C-74A-E6E + cheat + description:Get 5 rupees for each single rupee + code:054-EE9-E6E + cheat + description:Get 50 rupees for each single rupee + code:324-EE9-E6E + cheat + description:Get 255 rupees for each single rupee + code:FF4-EE9-E6E + cheat + description:Walk through walls. Can walk past the edge of walls and objects, but not through people. Be careful of entering doors from the wrong side. If you get stuck on the edge of a screen, try diagonal and straight movement in all directions. Works from locations in the water. Doesn't work for underground passages. + code:AF7-168-3B0 + +cartridge sha256:c95dd3d9cb798e86c28e3269554e458d434bf3277b96cadf5bc81cfacfb5ee60 + title:Legend of Zelda, The - Link's Awakening DX (USA, Europe) (SGB Enhanced) + cheat + description:Walk through walls. Be careful of entering doors from the wrong side. If you get stuck on the edge of a screen, try diagonal and straight movement in all directions to get yourself unstuck. Allows you to go through walls starting from locations in the water. Doesn't work for underground passages. + code:AF4-5B8-3B0 + +cartridge sha256:0b56b78a9e45452e98c33edd111234931f1e034dc097f6f23082eb8db6055474 + title:Legend of Zelda, The - Oracle of Ages (USA) + cheat + description:Defeat 1 enemy for fully grown Gashas/Maple meeting + code:002-46F-E69 + cheat + description:Infinite Seed/Bomb use on pick-up + code:007-D3E-E6E + cheat + description:Each Seed/Gasha/Bomb worth 99 + code:005-92B-E62 + cheat + description:Walk through walls. It's not hard to get stuck, so save where it's safe. + code:AFD-A5A-802 + +cartridge sha256:862a51368fb30539279d336b3fe193b43876d2cb15c87a36f5da517804ab3971 + title:Legend of Zelda, The - Oracle of Seasons (USA) + cheat + description:Defeat 1 enemy for fully grown Gashas/Maple meeting + code:002-46F-E69 + cheat + description:Infinite Seed/Bomb use on pick-up + code:007-ACE-E6E + cheat + description:Each Seed/Gasha/Bomb worth 99 + code:005-98B-E62 + cheat + description:Walk through walls. It's not hard to get stuck, so save where it's safe. + code:AFC-96A-802 + +cartridge sha256:68e708010f14daa6013370d43b9ee00a2305b1a95285e7daafa6642a0677b8c2 + title:Lethal Weapon (USA) + cheat + description:Infinite weapon energy + code:FA6-01E-4C1 + cheat + description:Infinite life energy (except falling down holes) + code:FAA-1DD-4C1+FAA-A5D-4C1 + cheat + description:No enemies + code:004-5BB-195 + cheat + description:Start with weapon energy on 1/2 + code:1E9-CEE-E6B + cheat + description:Start with life energy on 1/2 + code:239-C3E-E6B + +cartridge sha256:f15722ebebdae93e08bd6642d642614114f2d128778d6a131748c9855603e052 + title:Little Mermaid, The (USA) + cheat + description:Infinite energy + code:C98-22E-3BE + cheat + description:Infinite lives + code:00C-79F-3BE + cheat + description:Start with 2 lives + code:017-F1F-E66 + cheat + description:Start with 6 lives + code:057-F1F-E66 + cheat + description:Start with 10 lives + code:097-F1F-E66 + cheat + description:Start with 1 energy pt + code:018-96F-E66 + cheat + description:Start with 5 energy pts + code:058-96F-E66 + cheat + description:Start with 8 energy pts + code:088-96F-E66 + cheat + description:Start on level 2 + code:018-07F-195 + cheat + description:Start on level 3 + code:028-07F-195 + cheat + description:Start on level 4 + code:038-07F-195 + cheat + description:Start on level 5 + code:048-07F-195 + cheat + description:Start on level 6 + code:058-07F-195 + cheat + description:See end of game credits + code:068-07F-195 + +cartridge sha256:bf4cae27bd0dfdede3838d50f92d03cb7cd183a15091bd2a76c7b3fc7b3e718b + title:Madden '95 (USA, Europe) (SGB Enhanced) + cheat + description:Infinite play clock + code:00C-3BE-19E + cheat + description:Infinite game time + code:00C-62E-19E+F09-33C-6E9 + cheat + description:Start on second down + code:028-8ED-E6E + cheat + description:Start on third down + code:038-8ED-E6E + cheat + description:Start on fourth down + code:048-8ED-E6E + cheat + description:Down never increases + code:005-DED-19A+FAE-F0C-4C1 + +cartridge sha256:eabe2a1c9116871837ddb1d39d643621dc144c18490b5673bd8eedc88b8ceff9 + title:Malibu Beach Volleyball (USA) + cheat + description:Easier to score + code:03D-AAB-F7A + cheat + description:Computer can't score a point. If score is 0-0, makes you change court a lot. + code:00F-0CA-E6D + cheat + description:You always serve + code:00D-0EA-E6E+00D-E0A-E6E + +cartridge sha256:0d479d68a4ac800ab9fde8b3db016af718c13a979163b3eb34b00af96550cd3e + title:Mario's Picross (USA, Europe) (SGB Enhanced) + cheat + description:Infinite time + code:00B-118-19E + cheat + description:Mistakes don't decrease time + code:00C-8F8-A2C + +cartridge sha256:2c45623446cf82896830712223079e9be5e79b3e5faf550c07f92f082bef419e + title:Maru's Mission (USA) + cheat + description:Infinite energy + code:009-7CC-A2C+009-80C-808 + +cartridge sha256:33d16365318411f063edd9100c79458aabb7ea71bb1873e30f38b93814f0ec6e + title:Mega Man - Dr. Wily's Revenge (USA) + cheat + description:Invincibility + code:005-FAA-E6E+418-3F9-190 + cheat + description:Infinite weapons except Flash + code:002-09B-A22+FA1-5AA-4C1+FA9-64B-4C1 + cheat + description:Hit anywhere + code:018-61A-191+15A-3DD-A26+52B-47D-19F+008-1AD-5D4+00B-5AD-6EE+180-D2E-08A+110-D3E-D5A + cheat + description:Multi-jump + code:FAB-249-6EE+3FB-259-C43+E6B-279-193+01B-289-3B4+00B-2B9-3BE+1CC-CE9-3BA+18C-CF9-4CA + cheat + description:One hit kills + code:00B-62D-E6E+00C-87B-E6E + cheat + description:Moon jump + code:00B-2A9-D5F+18B-499-A22+18B-4A9-5D4+2CB-4B9-4C1 + +cartridge sha256:be3fc7ab2d7eb79a9e2538b090bdecc2694740f3beda933f34cb1e4059b10a11 + title:Mega Man II (USA) + cheat + description:Invincibility + code:C95-CEC-E69 + cheat + description:Infinite weapons + code:00A-14C-A28 + cheat + description:Multi-jump + code:012-45E-E6A+CD0-F0F-195+D40-F1F-195+0F0-F2F-195+C90-F3F-195+CD2-26E-081+F02-27E-5D7+002-28E-D55+182-2AE-4CA+002-44E-6EA + +cartridge sha256:7344a36fcfc8151098238529218762e44c5a1546fab7e7fd5d32927e06cbf5a8 + title:Mega Man III (USA) + cheat + description:Infinite energy + code:00C-099-3B7 + cheat + description:Infinite weapons + code:002-35B-A22+FA4-88A-4C1+FA8-A9A-4C1 + cheat + description:One hit kills + code:009-6ED-E6E+00F-25F-E6E + cheat + description:Laser barriers appear and explode immediately on Sparkman stage + code:009-77C-E6E + cheat + description:Takes 1 hit to kill Merciless Matt + code:019-53C-F76 + cheat + description:Takes 15 hits to kill Merciless Matt + code:0F9-53C-F76 + cheat + description:Multi-jump + code:FAE-3F9-6EE+3FE-409-C43+E6E-429-193+01E-439-3B4+00E-469-3BE+1C0-028-3BA+180-038-4CA + cheat + description:Start with 2 lives + code:02B-17F-E66 + cheat + description:Start with 6 lives + code:06B-17F-E66 + cheat + description:Start with 9 lives + code:09B-17F-E66 + +cartridge sha256:4d980ca46a83cd127312dbc445ed1a83e97ed7a8026dce6fdd22a01b1895781b + title:Mega Man IV (USA) + cheat + description:Invincibility + code:21F-EAA-E61 + cheat + description:Infinite energy + code:001-CE9-3B7 + cheat + description:Infinite lives + code:01C-45F-915 + cheat + description:Shoot more than 3 shots at a time + code:005-67B-A29 + cheat + description:Start with 1/4 energy + code:269-F6F-808 + cheat + description:Start with 1/2 energy + code:4B9-F6F-808 + cheat + description:Start with 3/4 energy + code:709-F6F-808 + cheat + description:Start with 1 lives + code:01C-AEF-E66 + cheat + description:Start with 5 lives + code:05C-AEF-E66 + cheat + description:Start with 9 lives + code:09C-AEF-E66 + +cartridge sha256:7a108770a7c1ad592b52d0c46d7ead422d0a20961abaafca3d40086e3f2f588f + title:Mega Man V (USA) (SGB Enhanced) + cheat + description:Invincibility + code:212-269-E61 + cheat + description:Infinite lives + code:01B-75F-915 + cheat + description:Infinite energy + code:004-1D9-3B7 + cheat + description:Walk through enemies (can still take damage from projectiles) + code:002-CDE + cheat + description:Hit anywhere + code:111-FAE-D5A+181-F9E-08A+11A-0E8-D5A+18A-0D8-08A + cheat + description:Multi-jump + code:FA6-829-6EE+406-839-A23+E66-859-193+016-869-3B4+006-899-3BE+1C8-719-C4A+1C8-799-3BA + cheat + description:One hit kills + code:001-85E-E6E+009-0ED-E6E+00A-4E8-E6E + cheat + description:Start with 1 lives + code:01B-EAF-E66 + cheat + description:Start with 5 lives + code:05B-EAF-E66 + cheat + description:Start with 9 lives + code:09B-EAF-E66 + cheat + description:Start with about 1/4 energy + code:269-44F-808 + cheat + description:Start with about 1/2 energy + code:4B9-44F-808 + cheat + description:Start with about 3/4 energy + code:709-44F-808 + +cartridge sha256:56a69d19ba26941a25adad8bdf17c7baba12245097e901999f4c897eec877ddb + title:Metal Gear Solid (USA) + cheat + description:Infinite ammo for all weapons + code:003-189-19E + cheat + description:Enemies don't see you + code:C94-A88-3B4+C94-E89-081 + +cartridge sha256:3080bcc2eb9965de463f5f4e02f0dabbb13b060e1654a18da8b50948c10af4a6 + title:Metroid II - Return of Samus (World) + cheat + description:Invincibility against enemies + code:C9E-E8D-E69 + cheat + description:Infinite energy + code:80F-6DD-7F6 + cheat + description:Infinite missiles + code:00F-36B-E6E + cheat + description:Hit anywhere + code:0D2-70C-3B2+182-6FC-2AA+182-E3A-2AA + cheat + description:Multi-jump + code:14D-46F-A26+98D-45F-91C+CDD-44F-E61+FA4-30E-4C1+FA4-61E-4C1 + +cartridge sha256:fedb0c8100987cb466c116a3ac3a6572675b6aa721a7a8930cec1ae39f677bc6 + title:Mickey's Chase (USA) + cheat + description:Invincibility after first hit + code:001-A8E-E6E + cheat + description:Infinite health + code:FAD-A0E-4C1 + cheat + description:Infinite lives + code:FA5-E2F-4C1 + cheat + description:Start with 99 lives + code:634-B6F-E66 + +cartridge sha256:70124937963d44c034d73e3e3c7ecf9c3440cdb934cd1a8b6fd4629381343d02 + title:Milon's Secret Castle (USA, Europe) + cheat + description:Protection against most hazards + code:FAD-368-4C1 + cheat + description:Infinite money on pick-up + code:FA7-8F9-4C1 + cheat + description:Each $ box is worth 99 + code:3E7-138-081+627-148-DC5+007-158-915 + cheat + description:Start with and keep double shot and shield + code:FAC-FD8-4C1+3CC-A8A-5D4 + cheat + description:Start with 3 energy bars + code:036-EA8-F7E + cheat + description:Start with 6 energy bars + code:066-EA8-F7E + cheat + description:Start with 9 energy bars + code:096-EA8-F7E + +cartridge sha256:d74962fe1750b3918c6b5e34dd30851df50e33eaeb27659097d52090c9803705 + title:Miner 2049er (USA) + cheat + description:Infinite time + code:002-239-E6E + cheat + description:Infinite lives + code:002-3DB-E6E + cheat + description:Nasties are invincible + code:039-CAF-E6A + cheat + description:Start with 2 lives + code:026-9ED-E66 + cheat + description:Start with 4 lives + code:046-9ED-E66 + cheat + description:Start with 8 lives + code:086-9ED-E66 + +cartridge sha256:f6d779c4882e032919903b4874dec1b6f06716911f77eb9f8acd1727215eb791 + title:Missile Command (USA, Europe) + cheat + description:Infinite missiles + code:002-9AE-19E+002-4BE-19E+20F-FDE-D56 + cheat + description:Invincible bases + code:FF6-BBD-191 + cheat + description:New York + code:02F-28E-E6A + cheat + description:London + code:04F-28E-E6A + cheat + description:Sydney + code:06F-28E-E6A + cheat + description:Paris + code:08F-28E-E6A + cheat + description:Moscow + code:0AF-28E-E6A + cheat + description:San Francisco + code:18F-28E-E6A + +cartridge sha256:84686cd3c77c533926fc2c56783613ecc5781de1bff7065e00112a69d17a5e69 + title:Mortal Kombat (USA, Europe) + cheat + description:Infinite health - P1 + code:005-94C-B31 + cheat + description:Infinite time + code:00C-B5E-3BE + cheat + description:Infinite continues + code:002-96D-B31 + cheat + description:Foot sweep does less damage + code:109-C7C-E6F + cheat + description:Foot sweep does more damage + code:FF9-C7C-E6F + cheat + description:1 continue + code:010-14B-F72 + cheat + description:5 continues + code:050-14B-F72 + cheat + description:10 continues + code:0A0-14B-F72 + cheat + description:Punches do less damage + code:109-AFC-6EE + cheat + description:Punches do more damage + code:FF9-AFC-6EE + cheat + description:Knees do less damage + code:109-BFC-E6F + cheat + description:Knees do more damage + code:FF9-BFC-E6F + cheat + description:Uppercuts do less damage + code:109-A7C-E60 + cheat + description:Uppercuts do more damage + code:FF9-A7C-E60 + cheat + description:Kicks to stomach do less damage + code:109-CFC-E6F + cheat + description:Kicks to stomach do more damage + code:FF9-CFC-E6F + cheat + description:Kicks to face do less damage + code:109-B7C-6E3 + cheat + description:Kicks to face do more damage + code:FF9-B7C-6E3 + cheat + description:Shoulder throws do less damage + code:10A-17C-E6F + cheat + description:Shoulder throws do more damage + code:FFA-17C-E6F + cheat + description:Sub-Zero's slide does less damage + code:10A-07C-A2F + cheat + description:Sub-Zero's slide does more damage + code:FFA-07C-A2F + cheat + description:Sonya's leg grab does less damage + code:10A-27C-6EF + cheat + description:Sonya's leg grab does more damage + code:FFA-27C-6EF + cheat + description:Kano's cannonball does less damage + code:10A-1FC-6EF + cheat + description:Kano's cannonball does more damage + code:FFA-1FC-6EF + cheat + description:Rayden's lightning does less damage + code:10A-5FC-7F5 + cheat + description:Rayden's lightning does more damage + code:FFA-5FC-7F5 + +cartridge sha256:29d69e0f71b692f348a0954cc3aaa86dcd9a32d8a7268ce6b76ba26b0c0e4629 + title:Mortal Kombat II (USA, Europe) + cheat + description:Infinite health + code:009-48B-91D + cheat + description:Infinite continues + code:00D-ABF-3BE + cheat + description:Infinite time + code:00C-55B-E6E + cheat + description:No continues + code:001-57F-F72 + cheat + description:1 continue + code:011-57F-F72 + cheat + description:3 continues + code:031-57F-F72 + cheat + description:9 continues + code:091-57F-F72 + cheat + description:15 continues + code:0F1-57F-F72 + cheat + description:Much faster timer + code:02C-55B-E6E + cheat + description:Timer starts at 30 + code:2C3-39D-800 + cheat + description:Timer starts at 40 + code:3C3-39D-800 + cheat + description:Timer starts at 50 + code:4C3-39D-800 + cheat + description:Timer starts at 60 + code:5C3-39D-800 + cheat + description:Player can't move from floor + code:006-2EB-3B7+000-1FA-3B7 + cheat + description:Complete round 1 and go to round 3 (disable after end of round) + code:3E1-79E-4CA+031-7AE-A2A+E01-7BE-2A9 + cheat + description:Complete round 1 and go to round 4 (disable after end of round) + code:3E1-79E-4CA+041-7AE-A2A+E01-7BE-2A9 + cheat + description:Computer can't move from floor + code:003-279-19E+003-249-19E + cheat + description:Normal punches do more damage + code:F40-E89-2AE + cheat + description:Uppercuts do less damage + code:311-009-3B9 + cheat + description:Back throws do less damage + code:311-3A9-E69 + cheat + description:Special moves (projectiles) do more damage + code:F41-5A9-E60 + +cartridge sha256:6c2733c0a57bbfe5075bec42e0735c685c934780db45b33f899f62dfea549f69 + title:Mortal Kombat 3 (USA) + cheat + description:Invincibility expect for throws and projectiles + code:00A-25E-081+00A-26E-7F5+7DA-27E-E69+14A-29E-D56+C8A-2AE-E69+C9D-57E-C49 + +cartridge sha256:abc725f10251ae954a23c46b7e33b101bc52203fed4ffad49018858d82361964 + title:Motocross Maniacs (USA) + cheat + description:Infinite tires on pick-up + code:FAD-CDE-4C1 + cheat + description:Infinite jet on pick-up + code:FAD-C7E-4C1 + cheat + description:Infinite time + code:00D-22D-E6E + cheat + description:Faster timer + code:02D-22D-E6E + cheat + description:Start with 7 nitros + code:079-E4F-F7A + cheat + description:Super fast bike + code:FA0-1ED-4C1+009-88E-B30 + +cartridge sha256:e493b87e119d61268af2f97c9e16e65daab3c8223c15261214656667108cc817 + title:Mouse Trap Hotel (USA) + cheat + description:Infinite lives + code:FA2-0CD-4C1 + cheat + description:Collect cookie for invincibility against balls, etc. + code:FA6-E9F-4C1+FA6-DAF-4C1 + cheat + description:Start with 4 lives + code:043-38F-E62 + cheat + description:Start with 6 lives + code:063-38F-E62 + cheat + description:Start with 8 lives + code:083-38F-E62 + +cartridge sha256:c19f7ec9ff29fa438d7ef189f81711dcaedaa55c86b192d6d9020f5f7dc22702 + title:Mr. Do! (USA) + cheat + description:Infinite lives + code:FA7-28C-4C1 + cheat + description:Keep 1 map layout thru game (still will progress from map to map, but layout stays the same) + code:3E8-2CE-191+098-2DE-C42+188-2EE-6EA + cheat + description:Start new game from level you died on + code:235-6AC-6E2+214-78D-4C1 + cheat + description:Start with 1 life + code:015-B2E-E66 + cheat + description:Start with 6 lives + code:065-B2E-E66 + cheat + description:Start with 9 lives + code:095-B2E-E66 + +cartridge sha256:ba1afcea3239c1acc9af228cebe6872f5547ad04480e71652e2e56dcd4e2f08e + title:Mysterium (USA) + cheat + description:Infinite lives + code:FA3-98C-4C1 + cheat + description:Max energy in battle. Works for enemies, disable to defeat them. + code:AF8-78C-E68 + cheat + description:Start with 1/2 energy + code:3AD-B38-E6A + cheat + description:Start with 1 life + code:01D-008-E66 + cheat + description:Start with 5 lives + code:05D-008-E66 + cheat + description:Start with 9 lives + code:09D-008-E66 + +cartridge sha256:424ca9fc4d842444a01c4dbf7375558035f4cb04a7d7056a4c1a1a18b769643d + title:Nail'n Scale (USA, Europe) + cheat + description:Infinite lives + code:00B-7EF-E65 + cheat + description:Start with 1 life + code:004-B5F-F7A + cheat + description:Start with 9 lives + code:084-B5F-F7A + +cartridge sha256:e8b4326469231ba798657cfa8032bc6c2000c0a61e11fbad8406711642a184eb + title:NFL Football (USA) + cheat + description:No game timer + code:009-34A-E6E + cheat + description:Computer can't score on its possessions + code:AF1-EDE-E64 + cheat + description:Touchdown worth 1 point + code:01F-59F-F72 + cheat + description:Touchdown worth 5 points + code:05F-59F-F72 + cheat + description:Touchdown worth 8 points + code:08F-59F-F72 + +cartridge sha256:ea284fad45e612ab2fcd721152ab815fe8e58062155ab6e182195f637d7b6da4 + title:Nintendo World Cup (USA, Europe) + cheat + description:Computer can't score + code:00E-2D8-19A + cheat + description:No timer + code:00D-2C8-E6E + cheat + description:1:59 each half + code:01C-DD8-E66 + cheat + description:4:59 each half + code:04C-DD8-E66 + cheat + description:6:59 each half + code:06C-DD8-E66 + cheat + description:9:59 each half + code:09C-DD8-E66 + +cartridge sha256:79b35e46b8258cccf8a858b6d66caf16855399fdc54bb1c0a5342e409908363f + title:Nobunaga's Ambition (USA) + cheat + description:Train samurais once and they have 100% skill level (must be Oda Nobunaga) + code:3EF-9FB-191 + cheat + description:Start with 75 loyalty pts (must be Oda Nobunaga) + code:4B1-5AA-2A2 + cheat + description:Start with 100 loyalty pts (must be Oda Nobunaga) + code:641-5AA-2A2 + cheat + description:Start with 50 town value pts (must be Oda Nobunaga) + code:321-56A-80E + cheat + description:Start with 75 town value pts (must be Oda Nobunaga) + code:4B1-56A-80E + cheat + description:Start with 100 town value pts (must be Oda Nobunaga) + code:641-56A-80E + cheat + description:Start with 50 castle defense pts (must be Oda Nobunaga) + code:321-5CA-D56 + cheat + description:Start with 75 castle defense pts (must be Oda Nobunaga) + code:4B1-5CA-D56 + cheat + description:Start with 100 castle defense pts (must be Oda Nobunaga) + code:641-5CA-D56 + cheat + description:Start with flood control level at 75 (must be Oda Nobunaga) + code:4B1-5BA-2A2 + cheat + description:Start with flood control level at 100 (must be Oda Nobunaga) + code:641-5BA-2A2 + cheat + description:Start with 2580 rice pts (must be Oda Nobunaga) + code:0AE-B6B-B3A+0AE-B9B-E6A + cheat + description:Start with 788 rice pts (must be Oda Nobunaga) + code:03E-B6B-B3A+03E-B9B-E6A + cheat + description:Start with 276 rice pts (must be Oda Nobunaga) + code:01E-B6B-B3A+01E-B9B-E6A + cheat + description:Start with 999 gold (must be Oda Nobunaga) + code:0AE-B6B-D56+0AE-B7B-E6A + cheat + description:Attributes for Oda Nobunaga are 100% (will show original values, answer no when asked if this is OK, then attributes will be 100%) + code:3E5-7EA-191 + +cartridge sha256:0b6670e44cc2edc6fbf32fc78f499e774cf0802019480f2bf7bdb836ee15c433 + title:Operation C (USA) + cheat + description:Invincibility + code:AFA-BFA-C45+77A-C0A-D53 + cheat + description:Hit anywhere + code:00A-CAC-91A+C3A-E4C-919+C6A-F5C-191 + cheat + description:Multi-jump + code:005-C0A-B3F+5A0-E6F-195+520-E7F-195+550-EAF-195+7A0-E9F-195+CD0-E5F-195+CD0-E8F-195+C90-EBF-195+E55-BFA-083 + +cartridge sha256:efcce0d4264fbfff4b1b3a0843a681194b2d7a597e842d2895c2eadcfc6998c3 + title:Out of Gas (USA) + cheat + description:Infinite lives + code:FA5-DDF-4C1 + cheat + description:Collect only 1 canister to complete each stage + code:AF8-ECE-191 + cheat + description:Start with 2 lives + code:021-ACF-E66 + cheat + description:Start with 4 lives + code:041-ACF-E66 + cheat + description:Start with 8 lives + code:081-ACF-E66 + +cartridge sha256:8b81c75dd11e24ba5e1d2f439a6fabf7313024829df397409a20dd37995122cb + title:Pagemaster, The (USA) (SGB Enhanced) + cheat + description:Invincibility + code:008-36B-19E + cheat + description:Infinite Help Books + code:00F-348-19E + cheat + description:Don't flash at all when you start a new stage + code:000-95B-19A + cheat + description:Flash longer when you start a new stage + code:FF0-95B-19A + cheat + description:Get a Help Book for every Gold Token + code:01F-D1E-912 + cheat + description:Get a Help Book for every 2 Gold Tokens + code:02F-D1E-912 + cheat + description:Get a Help Book for every 10 Gold Tokens + code:0AF-D1E-912 + cheat + description:Get a Help Book for every 50 Gold Tokens + code:32F-D1E-912 + cheat + description:Get a Help Book for every 99 Gold Tokens + code:63F-D1E-912 + cheat + description:Start in the Adventure World with 1 life + code:011-BFF-F7E+001-C3F-5D4 + cheat + description:Start in the Fantasy World with 2 lives + code:021-BFF-F7E+001-C3F-5D4 + cheat + description:Start with 1 life + code:011-BFF-F7E + cheat + description:Start with 3 lives + code:031-BFF-F7E + cheat + description:Start with 7 lives + code:071-BFF-F7E + cheat + description:Start with 10 lives + code:0A1-BFF-F7E + cheat + description:Start with 15 lives + code:0F1-BFF-F7E + cheat + description:Start with 11,111,111 points + code:3C1-CDF-5D4 + +cartridge sha256:5c357df199e755eae719588a3424d49bc5212289922f11968e47954276941d6a + title:Paperboy 2 (USA, Europe) + cheat + description:Infinite papers + code:004-C09-3BE + cheat + description:Infinite lives + code:006-91B-3BE + cheat + description:Go on to next day after completing Monday + code:007-0CB-F72 + cheat + description:Start with 15 papers - 1st life only + code:0FC-C6C-C42 + cheat + description:Start with 20 papers - 1st life only + code:14C-C6C-C42 + cheat + description:Start with 10 lives - Paperboy + code:0AA-E6C-F7E + cheat + description:Start with 20 lives - Paperboy + code:14A-E6C-F7E + +cartridge sha256:3bcf1b2fe43907d96e58b9aca893a9124bfb3c35774926279f9368a975665086 + title:Parodius (Europe) + cheat + description:Infinite lives + code:FA3-C6C-4C1 + cheat + description:Infinite super shields once collected + code:FAB-5D8-4C1 + cheat + description:Start with super shields and triple firing + code:FFB-D3D-E6A+FFB-D6D-E6A + cheat + description:Start with 5 lives + code:05A-93D-E66 + cheat + description:Start with 8 lives + code:08A-93D-E66 + cheat + description:Start with 11 lives + code:0BA-93D-E66 + +cartridge sha256:ec2420a8d1b129379435e9a217ef8e6be7fcece10a17d72affa8b1b2449888cb + title:Pinball Dreams (USA, Europe) + cheat + description:Infinite balls + code:008-18F-3BA + cheat + description:Start with 5x bonus, lose it if you collect any other bonus + code:3EB-EDF-4C1+04B-EEF-4C7+00B-EFF-A2D + cheat + description:No tilt - shake the table as much as you want + code:004-BAC-4CA+004-BBC-B32 + cheat + description:Collect 2x bonus and get 6x bonus + code:054-C7D-E62 + cheat + description:Start with 1 ball + code:018-1BF-E66 + cheat + description:Start with 4 balls + code:048-1BF-E66 + cheat + description:Start with 7 balls + code:078-1BF-E66 + cheat + description:Start with 9 balls + code:098-1BF-E66 + +cartridge sha256:027a8bb2843c3f96373ca60830f58fbc2fcf15d51756649e002b87a97f438a41 + title:Play Action Football (USA) + cheat + description:Always kick at full power + code:3E5-DFC-6EA+405-E0C-4C9+005-E5C-19E + cheat + description:Infinite time + code:00A-6BD-19E + cheat + description:Infinite downs + code:013-2A9-E69 + cheat + description:Only get 2 downs + code:02B-84E-F7A + cheat + description:Only need 5 yards for 1st down + code:053-419-C42 + +cartridge sha256:4a1c9750f77deffb8e003b8938d2ffe5f520fb43143aedd309909b8a9907856d + title:Popeye 2 (USA) + cheat + description:Invincibility after first hit until end of level + code:00E-83B-19E + cheat + description:Infinite Pows + code:FA3-C59-4C1 + cheat + description:Infinite lives + code:FA3-AFF-4C1 + cheat + description:Infinite time - disable to advance in some areas + code:2A2-02B-A22 + cheat + description:Infinite continues + code:00A-1AA-19E + cheat + description:Super code - more lives and power + code:88B-68B-E66 + cheat + description:Start with 1 Pow after 1st life + code:013-A7F-E66 + cheat + description:Start with 7 Pows after 1st life + code:073-A7F-E66 + cheat + description:Start with no continues + code:003-F7A-F7E + cheat + description:Start with 2 continues + code:023-F7A-F7E + cheat + description:Start with 9 continues + code:093-F7A-F7E + +cartridge sha256:e1b69e85caebf764bfa6cece5c1d33b67b370cf055480f309644b937e4a7ebdb + title:Prophecy - The Viking Child (USA) + cheat + description:Infinite lives + code:FAE-04C-4C1 + cheat + description:Infinite energy + code:FAD-F5C-4C1 + cheat + description:Each coin gives lots of money + code:00D-9BD-19B + cheat + description:Start with 25 energy - 1st life + code:194-A5F-667 + cheat + description:Start with 50 energy - 1st life + code:324-A5F-667 + cheat + description:Start with 4 lives + code:034-A0F-E6E + cheat + description:Start with 7 lives + code:064-A0F-E6E + cheat + description:Start with 10 lives + code:094-A0F-E6E + +cartridge sha256:567aef8ea27486a4fa38ef4a4ae6ebae2a9138dc8a6a675d155895936e1318d8 + title:Pyramids of Ra (USA) + cheat + description:Energy bar doesn't go down when you make a move + code:FA5-8EB-4C1 + cheat + description:Only 1 pt. of energy per move on first attempt at each level (instead of 3) + code:A2A-C48-6EC+3CA-C68-19B+FAA-C38-4C1 + cheat + description:Start on level 100 + code:641-AB4-E6E+001-ACF-E6A + cheat + description:Start on level 300 + code:2C1-ABF-E6E+011-ACF-E6A + cheat + description:Start on level 500 + code:F41-ABF-E6E+011-ACF-E6A + +cartridge sha256:ed110933b5a41ed89d2b980e6e984733833fa6b2c15e5235eff1f5df54175df4 + title:Qix (World) + cheat + description:Invincibility + code:AFE-DBC-3B4 + +cartridge sha256:7d8e122f6f70f6ca49521f2c24fd987e91f621977da2912702285735438be901 + title:Quarth (USA, Europe) + cheat + description:Select up to level 5 + code:054-9EA-E66 + cheat + description:Super turbo ship + code:00B-31D-08F + cheat + description:Blocks don't drop (push Up to bring blocks down) + code:AF6-32E-A28 + cheat + description:Blocks drop faster + code:3E6-2BE-081+506-2CE-2AB+006-2DE-F79 + cheat + description:Blocks drop super fast + code:3E6-2BE-081+806-2CE-2AB+006-2DE-F79 + +cartridge sha256:4e624ad741077f574c1d0b57cbc45171ed4ca9f23fa89dfd8f282897aa53ab9a + title:Q Billion (USA) + cheat + description:Pressing Select in Game B once gives you 246 seconds + code:00B-9FE-C42 + cheat + description:Infinite timer + code:007-55E-19E + cheat + description:Level select - Game A + code:3EB-61F-08A+0DB-62F-B3E+00B-63F-08F + +cartridge sha256:b3f2838cb64dfa12f93ab4767c3b0786cba0993015fefe1f592146f9d8f47d40 + title:Radar Mission (USA, Europe) + cheat + description:Game B - Infinite money + code:003-33D-3BE + cheat + description:Game B - Move in 1 direction only + code:003-CCA-3BE + cheat + description:Game B - Destroyed fleet disappears from radar screen but game doesn't end + code:00C-C6A-3BE + cheat + description:Game B - Start with 1 money bag + code:011-E0D-E66 + cheat + description:Game B - Start with 1 extra money bag + code:041-E0D-E66 + +cartridge sha256:9e30f9c36cfa1bc1fd6f111fa38a43f3c5907c26d81a65309279eec54a3d05d6 + title:Raging Fighter (USA, Europe) + cheat + description:Infinite energy + code:004-E0B-E6D+007-1AE-3B7 + cheat + description:Infinite time + code:009-1FB-A22 + cheat + description:4th difficulty level - go to options, set difficulty, press Left 3 times (won't show anything), then exit + code:3E1-F2A-4CA+041-F3A-E62+771-F4A-3BA + cheat + description:Start on level 4 - 1P tournament only + code:3EE-5BD-4C1+03E-5CD-4CB+00E-5DD-E61 + cheat + description:Start on final level - 1P tournament only + code:3EE-5BD-4C1+07E-5CD-4CB+00E-5DD-E61 + cheat + description:Start each fight with 10 seconds + code:10A-9AA-89C + cheat + description:Start with 1/2 time + code:50A-9AA-89C + cheat + description:Start with 3/4 time + code:75A-9AA-89C + +cartridge sha256:ad5d681fa599b6cf9dae135c304317ac41f33bee0a5a583d7fa2a178ca66506f + title:Rampart (USA, Europe) + cheat + description:Infinite time - levels don't end, enable at game play screen, disable after battle mode, enable to rebuild castle, disable to go on + code:003-9CF-3BE + cheat + description:Infinite lives + code:017-0EB-F79 + cheat + description:Infinite cannons + code:01E-B3B-F79 + cheat + description:Have 6 seconds to rebuild castle walls + code:3E0-29B-081+090-2AB-7F5+000-2BB-F7D + cheat + description:Have 66 seconds to rebuild castle walls + code:3E0-29B-081+440-2AB-7F5+000-2BB-F7D + cheat + description:Have 118 seconds to rebuild castle walls + code:3E0-29B-081+770-2AB-7F5+000-2BB-F7D + cheat + description:Levels last 10 seconds + code:3E0-40B-081+1A0-41B-B32+000-42B-F71 + cheat + description:Levels last 25 seconds + code:3E0-40B-081+2A0-41B-B32+000-42B-F71 + cheat + description:Levels last 50 seconds + code:3E0-40B-081+430-41B-B32+000-42B-F71 + +cartridge sha256:46cfbba977f7d4cb8df51d5cb51f00dc0a4d9c129868a1ed88f2b0fa97454905 + title:Ren & Stimpy Show, The - Space Cadet Adventures (USA) + cheat + description:Infinite lives + code:F07-54E-6E9 + cheat + description:Infinite energy except when you fall into pits + code:F07-33E-6E9 + cheat + description:Start with 2 life + code:01D-2EA-E62 + cheat + description:Start with 6 lives + code:05D-2EA-E62 + cheat + description:Start with 9 lives + code:08D-2EA-E62 + cheat + description:Start with 5 energy - 1st life only + code:04D-32A-E66 + cheat + description:Start with 6 energy - 1st life only + code:05D-32A-E66 + cheat + description:Start with 7 energy - 1st life only + code:06D-32A-E66 + cheat + description:Start with 4 energy - after 1st life + code:047-5CE-E66 + cheat + description:Start with 5 energy - after 1st life + code:057-5CE-E66 + cheat + description:Start with 6 energy - after 1st life + code:067-5CE-E66 + +cartridge sha256:9a97678cbd8da02c8763e977674e17f460c06ea8b73bad35c52fe6817f506d44 + title:Resident Evil Gaiden (USA) + cheat + description:Infinite ammo on pick-up + code:004-26B-E65 + cheat + description:Infinite Herbs + code:004-E88-3BE + cheat + description:All Herbs cure poison + code:004-908-C49 + +cartridge sha256:d84a2382b358d83a0891d40b2de65494f060d8be1a048d5aa8721282218b04b6 + title:Pinball - Revenge of the 'Gator (USA, Europe) + cheat + description:Infinite supply of balls + code:007-E1F-3BE + cheat + description:Disable left flipper + code:21F-24D-D5D + cheat + description:Disable right flipper + code:C9F-2AD-7F1 + cheat + description:Start with 1 ball + code:016-EDF-E66 + cheat + description:Start with 9 balls + code:096-EDF-E66 + +cartridge sha256:c6d02170734d6b533d4599b6fca10ac83141e5ffe4902c4a98001aa61c00dffc + title:RoboCop 2 (USA) + cheat + description:Infinite health on scrolling levels + code:C95-9CE-C49 + cheat + description:Infinite health on ED-209 (tm) levels + code:AF4-D9A-3B7 + cheat + description:Infinite lives + code:B60-C2D-3BE + cheat + description:Infinite time - except stages 3 and 8 + code:C95-48E-C49 + cheat + description:Start with 2 lives + code:02A-E8E-F7A + cheat + description:Start with 5 lives + code:05A-E8E-F7A + +cartridge sha256:9fb0e41e4c8afe737a688dbdc1b6f7019874f7e9ef4c0a27cba2b8be329ce45b + title:RoboCop vs. The Terminator (USA) + cheat + description:Infinite energy + code:FAE-67B-4C1 + cheat + description:Start on level 2 + code:01D-7DD-E6A + cheat + description:Start on level 3 + code:02D-7DD-E6A + cheat + description:Start on level 4 + code:03D-7DD-E6A + cheat + description:Start on level 5 + code:04D-7DD-E6A + cheat + description:Start on level 6 + code:05D-7DD-E6A + cheat + description:Start with 01010101 points + code:01D-5DD-56A + cheat + description:Start with very little energy - 1st life + code:01D-58D-F76 + cheat + description:Start with more energy - 1st life + code:15D-58D-F76 + cheat + description:Start with very little energy - 2nd life + code:01E-E0B-F76 + cheat + description:Start with more energy - 2nd life + code:15E-E0B-F76 + +cartridge sha256:92e8d1acd4d2d3297a961409d4bb0ed49c784be4a6e91cfceabd05ab11894f3d + title:Roger Clemens' MVP Baseball (USA) + cheat + description:No walks + code:014-68A-F7D + cheat + description:No strikeouts + code:014-87A-F7D + cheat + description:Infinite outs (except strikeouts, base runners will still be taken out) + code:016-B4C-F7D + cheat + description:No outs are called, except strikeouts + code:016-AFC-E66+01B-87C-E66 + cheat + description:No scoring - disable to score runs + code:009-46B-3B7+009-61B-3B7 + +cartridge sha256:e3d0b1ddea8b4ada14c3bb5e990171e6b2e26935d9dbc15e5de90fb5f7f9595d + title:Rolan's Curse (USA) + cheat + description:Infinite energy + code:F0C-96C-6E9 + cheat + description:Start with 2 energy pts + code:025-F5E-F7A + cheat + description:Start with 6 energy pts + code:065-F5E-F7A + +cartridge sha256:cf3f8f41498cdd32f5b3ee0cdccde1901b073798f3edac1a7d9ccc0141cb16be + title:Rolan's Curse II (USA) + cheat + description:Infinite HP + code:FOE-86C-6E9 + cheat + description:Infinite magic + code:F0E-01F-6E9 + cheat + description:Takes 9 MP to use Electric ball + code:094-59A-E6E + cheat + description:Takes 2 MP to use Electric ball + code:024-59A-E6E + cheat + description:Starts you from a new place with power-ups + code:3C3-72E-5D4 + +cartridge sha256:e0a07f84198e062c9ba8d617ef15679ba044f96510e5c62309ea1f743499a2c9 + title:Samurai Shodown (USA, Europe) (SGB Enhanced) + cheat + description:Computer takes all damage - even when you get hit + code:3EB-60D-7F1 + cheat + description:Infinite time + code:FA2-46D-4C1 + cheat + description:Start timer at 30 seconds + code:3EF-80E-D57+1EF-81E-08F + cheat + description:Start timer at 46 seconds + code:3EF-80E-D57+2EF-81E-08F + cheat + description:Start timer at 62 seconds + code:3EF-80E-D57+3EF-81E-08F + cheat + description:Start timer at 78 seconds + code:3EF-80E-D57+4EF-81E-08F + cheat + description:Start timer at 94 seconds + code:3EF-80E-D57+5EF-81E-08F + cheat + description:Start timer at 110 seconds + code:3EF-80E-D57+6EF-81E-08F + cheat + description:Start timer at 126 seconds + code:3EF-80E-D57+7EF-81E-08F + cheat + description:Start timer at 142 seconds + code:3EF-80E-D57+8EF-81E-08F + cheat + description:Start timer at 158 seconds + code:3EF-80E-D57+9EF-81E-08F + cheat + description:Both players start with 1/3 energy + code:11F-86E-3B6 + cheat + description:Both players start with 2/3 energy + code:21F-86E-3B6 + cheat + description:Both players start with more energy + code:FFF-86E-3B6 + cheat + description:Always fight Genan Shiranui + code:3E8-9A9-2AA+008-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Galford + code:3E8-9A9-2AA+018-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Haohmaru + code:3E8-9A9-2AA+028-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Ukyo Tachibana + code:3E8-9A9-2AA+038-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Charlotte + code:3E8-9A9-2AA+048-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Tam Tam + code:3E8-9A9-2AA+058-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Earthquake + code:3E8-9A9-2AA+068-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Nakoruru + code:3E8-9A9-2AA+078-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Wan Fan + code:3E8-9A9-2AA+088-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Jubei Yagyo + code:3E8-9A9-2AA+098-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Hanzo Hattori + code:3E8-9A9-2AA+0A8-9B9-D5E+E08-9C9-2A9 + cheat + description:Always fight Kyoshiro Senryo + code:3E8-9A9-2AA+0B8-9B9-D5E+E08-9C9-2A9 + +cartridge sha256:384885e8eb8c7396a8c7df08729f61022cc740b3234a8d35bebe17cc7aef3c71 + title:SeaQuest DSV (USA, Europe) (SGB Enhanced) + cheat + description:Invincibility + code:00E-04B-19E + cheat + description:Infinite lives + code:001-EB8-E6E + cheat + description:Lose most energy after first hit + code:AFE-04B-19E + cheat + description:Start with super score + code:03B-37D-E6A + cheat + description:Start with very little hull energy + code:011-FCC-C42 + cheat + description:Start with 1/2 hull energy + code:051-FCC-C42 + cheat + description:Start with 3/4 hull energy + code:071-FCC-C42 + cheat + description:Start with 2 lives + code:01B-2DD-F7A + cheat + description:Start with 5 lives + code:04B-2DD-F7A + cheat + description:Start with 10 lives + code:09B-2DD-F7A + cheat + description:Start with 15 lives + code:0EB-2DD-F7A + +cartridge sha256:52924262f2c60fc1c387a92bfdb43835c84968daf4ba465e7cc6627774e7b8a5 + title:Serpent (USA) + cheat + description:Infinite missiles on pick-up + code:00F-B0E-E69 + cheat + description:Start with 5 missiles + code:057-C9D-E6A + cheat + description:Start with 8 missiles + code:087-C9D-E6A + cheat + description:Start with 15 missiles + code:0F7-C9D-E6A + cheat + description:Start with smaller tail + code:157-C6D-4CA + cheat + description:Start with longer tail + code:407-C6D-4CA + +cartridge sha256:c8979ad731912452dabedff2c9fb23b19aa68cfdedbf5e99fec902547ce1bb76 + title:Simpsons, The - Bart & the Beanstalk (USA, Europe) + cheat + description:Invincibility + code:C97-2CC-E69 + cheat + description:Infinite energy + code:FA7-42C-4C1 + cheat + description:Infinite lives + code:002-83E-E6E + cheat + description:Infinite fire crackers + code:00A-608-19E + cheat + description:Start with 1 life + code:001-ADF-E66 + cheat + description:Start with 5 lives + code:041-ADF-E66 + cheat + description:Start with 10 lives + code:091-ADF-E66 + cheat + description:Start with 1/4 energy + code:106-37E-917 + cheat + description:Start with 1/2 energy + code:306-37E-917 + cheat + description:Start with 3/4 energy + code:456-37E-917 + +cartridge sha256:6ecab90879e06226ed6b2f6bdeb2d3ffa0736ee77c2132891083671465dd6934 + title:Simpsons, The - Bart vs. the Juggernauts (USA, Europe) + cheat + description:Infinite time on all games + code:008-A6F-3B7 + cheat + description:Always qualify with enough money + code:0A6-EB9-4C2 + cheat + description:See end sequence + code:043-5B9-F76 + cheat + description:Start on week 2 + code:023-5B9-F76 + cheat + description:Start on week 3 + code:033-5B9-F76 + cheat + description:Capt. Lance Murdock's Skateboard Bash & Crash - Infinite lives + code:FAF-829-4C1 + cheat + description:Capt. Lance Murdock's Skateboard Bash & Crash - Start with 1 life + code:01E-A89-F76 + cheat + description:Capt. Lance Murdock's Skateboard Bash & Crash - Start with 2 lives + code:02E-A89-F76 + cheat + description:Springfield Nuclear Power Plant Bop 'till You Drop - No hits against you + code:FA8-F38-4C1 + cheat + description:Herman's Military Minefield Mayhem - Infinite hits + code:FAB-F28-4C1 + cheat + description:Herman's Military Minefield Mayhem - Infinite runs + code:FA2-848-4C1 + cheat + description:Kwik-E-Mart Doggie Dodge - Infinite chances + code:FA2-279-4C1 + cheat + description:Kwik-E-Mart Doggie Dodge - Start with 3 lives + code:03D-89A-916 + cheat + description:Kwik-E-Mart Doggie Dodge - Start with 6 lives + code:06D-89A-916 + cheat + description:Kwik-E-Mart Doggie Dodge - Start with 9 lives + code:09D-89A-916 + +cartridge sha256:534478ebd2558ab6a871540062fadbb0ea27808d7f6860942b2e6805fd15e87b + title:Simpsons Itchy & Scratchy, The - Miniature Golf Madness (USA, Europe) + cheat + description:Invincibility + code:00A-07A-C49 + cheat + description:Invincible after getting hit + code:00A-24A-3BE + cheat + description:Infinite lives + code:00A-24D-E6E + cheat + description:Always get a hole in one + code:009-0E9-E6E + cheat + description:Start with 1 life + code:000-7D9-CCE + cheat + description:Start with 5 lives + code:040-7D9-CCE + cheat + description:Start with 15 lives + code:0E0-7D9-CCE + +cartridge sha256:a1e0c6d8385ab8c39569217f28cb335ccac8c85d31e01c9a2343c79494164478 + title:Snoopy - Magic Show (USA, Europe) + cheat + description:Start on level 2 + code:3E7-3FD-4C1+027-40D-087+007-41D-E65 + cheat + description:Start on level 5 + code:3E7-3FD-4C1+057-40D-087+007-41D-E65 + cheat + description:Start on level 9 + code:3E7-3FD-4C1+097-40D-087+007-41D-E65 + cheat + description:Start with 22 seconds + code:108-49A-E6B + cheat + description:Start with 63 seconds + code:3F8-49A-E6B + cheat + description:Start with 100 seconds + code:648-49A-E6B + +cartridge sha256:fece5b09e599c1f8116602fcabd558cc8dbbfe1c6c253853c5e871b0d732c11c + title:SolarStriker (World) + cheat + description:Infinite lives + code:00C-D6F-3BE + cheat + description:When you pick up a power-up, go straight to max power + code:3EF-65E-191+04F-66E-F7E + cheat + description:Bullets are mega-powerful, almost invisible, when you pick up a power-up + code:3EF-65E-191+0BF-66E-F7E + cheat + description:No loss of power-ups on dying + code:006-45E-C41 + cheat + description:Stay on same level + code:00D-EEF-3BA + cheat + description:Start with 2 lives + code:015-D0F-E62 + cheat + description:Start with 6 lives + code:055-D0F-E62 + cheat + description:Start with 10 lives + code:095-D0F-E62 + cheat + description:Start on stage 2 + code:025-0AF-E6E + cheat + description:Start on stage 3 + code:035-0AF-E6E + cheat + description:Start on stage 4 + code:045-0AF-E6E + cheat + description:Start on stage 5 + code:055-0AF-E6E + cheat + description:Start on stage 6 + code:065-0AF-E6E + +cartridge sha256:6ffe31b21d429801b8e5a460e58bd857e41aef888d19297fc558cf25def0d10d + title:Spanky's Quest (USA) + cheat + description:Infinite lives + code:000-60E-19E + cheat + description:Mega ball power-ups - hit it with your head once for full power + code:074-1ED-E6A + cheat + description:Start with 1 life + code:00B-96D-E62 + cheat + description:Start with 6 lives + code:05B-96D-E62 + cheat + description:Start with 9 lives + code:08B-96D-E62 + cheat + description:Start on tower 1, stage 5 (disable after starting stage) + code:3ED-68D-C45+04D-69D-3B6 + cheat + description:Start on tower 1, stage 10 (disable after starting stage) + code:3ED-68D-C45+09D-69D-3B6 + cheat + description:Start on tower 1, last stage (disable after starting stage) + code:3ED-68D-C45+0FD-69D-3B6 + +cartridge sha256:7b96653450c5fb4522a77d46ecfa50d479b3dac28bafb1a13e416e43c42caae3 + title:Speedball 2 - Brutal Deluxe (USA, Europe) + cheat + description:Get lots of money + code:99D-CDB-F7A + cheat + description:Infinite money + code:FAA-E4C-4C1 + cheat + description:No timer + code:00E-D99-3BE + cheat + description:Opponents can't score any points except from bounced stones + code:00C-30F-08B + +cartridge sha256:5bfae99484fe74c42b55a0dd8835861cfeb7d05590882aab8f4253e4e7138b92 + title:Speedy Gonzales (USA, Europe) + cheat + description:Infinite lives + code:FAC-A9B-4C1 + cheat + description:Infinite time + code:FA9-40B-4C1 + cheat + description:Start 1st game with 1 life + code:00A-8A8-E66 + cheat + description:Start 1st game with 7 lives + code:06A-8A8-E66 + cheat + description:Start 1st game with 10 lives + code:09A-8A8-E66 + cheat + description:Start in Forest Zone after entering password 500999 + code:024-5A9-F72+004-5B9-A28 + cheat + description:Start in Desert Zone after entering password 500999 + code:034-5A9-F72+004-5B9-A28 + cheat + description:Start in County Zone after entering password 500999 + code:044-5A9-F72+004-5B9-A28 + cheat + description:Start in Cheese Island Zone after entering password 500999 + code:054-5A9-F72+004-5B9-A28 + cheat + description:Start continued games with 1 life + code:00D-87B-E66 + cheat + description:Start continued games with 7 lives + code:06D-87B-E66 + cheat + description:Start continued games with 10 lives + code:09D-87B-E66 + cheat + description:Start with 1/2 time + code:05E-F6C-C4E + cheat + description:Start with 3/4 time + code:07E-F6C-C4E + +cartridge sha256:89c4151a31f00dc0f20133ee5ec8f71f3023331de93e017e97d66dc497eb2aa9 + title:Spider-Man 2 (USA, Europe) + cheat + description:Infinite lives + code:FA6-FBE-4C1 + cheat + description:Infinite energy + code:FA6-C4E-4C1 + cheat + description:Infinite web power + code:FAD-F6E-4C1 + cheat + description:1 energy point after life lost + code:016-EEE-195 + cheat + description:Start with 1 life + code:00F-78E-E66 + cheat + description:Start with 5 lives + code:04F-78E-E66 + cheat + description:Start with 10 lives + code:09F-78E-E66 + cheat + description:Start with 1 energy point + code:01F-5BE-195 + cheat + description:Start with 4 web points - 1st life only + code:04F-73E-B3A + cheat + description:Start with 5 web points - 1st life only + code:05F-73E-B3A + cheat + description:Start with 9 web points - 1st life only + code:09F-73E-B3A + +cartridge sha256:664dae41e2d08070ead51e76c2d6865e52a122566cf79203b7c6c496968ded6e + title:Spider-Man 3 - Invasion of the Spider-Slayers (USA, Europe) + cheat + description:Infinite energy + code:FA7-ECE-4C1 + cheat + description:Infinite lives + code:FA8-25E-4C1 + cheat + description:Need to shoot 1 enemy to clear level 1-1 + code:01E-3AD-B3A + cheat + description:Start 1st life with 1/2 energy + code:723-ABD-195 + cheat + description:Start lives after 1st with 1/2 energy + code:728-18E-195 + cheat + description:Start 1st level with 1/2 time + code:FA7-6FB-4C1 + cheat + description:Start 1st level with 255 seconds on timer + code:FFE-2DD-B30 + +cartridge sha256:7275c3af129971c53ce901321f6ca85b414ebd84574c420d66c38aa87c219fe3 + title:Spot - The Cool Adventure (USA) + cheat + description:Infinite energy (hearts) except when you fall off screen + code:FA9-0AC-4C1 + cheat + description:Start with 4 lives + code:045-76D-F7A + cheat + description:Start with 6 lives + code:065-76D-F7A + cheat + description:Start with 9 lives + code:095-76D-F7A + cheat + description:Start with 15 lives + code:0F5-76D-F7A + cheat + description:Start with 25 bonus discs + code:255-80D-E6A + cheat + description:Start with 59 bonus discs + code:505-80D-E6A + cheat + description:Start with 5 energy (easy level) + code:052-F7B-F7E + cheat + description:Start with 8 energy (easy level) + code:082-F7B-F7E + cheat + description:Start with 10 energy (easy level) + code:082-F7B-F7E + cheat + description:Start with 5 energy (hard level) + code:055-7BD-E66 + cheat + description:Start with 8 energy (hard level) + code:085-7BD-E66 + cheat + description:Start with 10 energy (hard level) + code:082-7BD-E66 + +cartridge sha256:966883149824ad2542a03a6402278d1397cdf0cbc0a7ba8410265410426ebfb9 + title:Spud's Adventure (USA) + cheat + description:Infinite lives + code:002-67E-19E + cheat + description:Begin each new screen with a key-except 1st screen + code:007-5FE-5D4 + cheat + description:1 EXP pt. for killing a bad guy + code:3E1-D1E-2A9+011-D2E-915 + cheat + description:5 EXP pts. for killing a bad guy + code:3E1-D1E-2A9+051-D2E-915 + cheat + description:9 EXP pts. for killing a bad guy + code:3E1-D1E-2A9+091-D2E-915 + cheat + description:Start with 2 life + code:013-C8E-E62 + cheat + description:Start with 6 lives + code:053-C8E-E62 + cheat + description:Start with 10 lives + code:093-C8E-E62 + +cartridge sha256:f0f1f547332965963ae2f8b3f3b5fd62203e0690cc0299d38e1a3aa56f6a263b + title:Spy vs Spy - Operation Boobytrap (USA) + cheat + description:Infinite time + code:002-D2A-3BE + cheat + description:Both spies start with 4 energy + code:046-9EE-C42 + cheat + description:Both spies start with 6 energy + code:066-9EE-C42 + cheat + description:Both spies start with 8 energy + code:086-9EE-C42 + cheat + description:After death, start with 4 energy - white spy + code:04D-84B-C42 + cheat + description:After death, start with full energy - white spy + code:08D-84B-B42 + cheat + description:No loss of energy during fight - both spies + code:005-14B-3BE + cheat + description:Other spy's punches do not affect your energy + code:005-03B-80A + cheat + description:Walking over floor flowers doesn't affect your energy + code:FA0-5CA-4C1 + cheat + description:Traps do not affect energy - white spy + code:00A-76B-E62 + +cartridge sha256:5b6bdf85e9083f328449b1316f5dd9c2789f4a57bdac5b16d74fe10bbea1b03c + title:Square Deal - The Game of Two-Dimensional Poker (USA) + cheat + description:Infinite time on pause counter + code:01D-A0E-F79 + cheat + description:Timer starts at 30 + code:1EC-83E-10A + cheat + description:No time on pause counter + code:00C-83E-10A + cheat + description:Select up to level 10 in level select + code:0A4-D8D-F7E + cheat + description:Start with 1 replay + code:3E3-AFD-C4E+013-B0D-193 + cheat + description:Start with 3 replays + code:3E3-AFD-C4E+033-B0D-193 + cheat + description:Start with 9 replays + code:3E3-AFD-C4E+093-B0D-193 + +cartridge sha256:2cdf2edac4e6230e063c867c60f92d5bb5f37969a19a32fb65c33fe9fafaa378 + title:Stargate (USA, Europe) + cheat + description:Tile counter doesn't work + code:008-22B-E6E + cheat + description:Tiles all look blank but aren't + code:C92-74D-C49 + cheat + description:The bottom of the tiles are always tile one + code:0E9-7DB-80E+019-7EB-D53 + cheat + description:The bottom of the tiles are always tile two + code:0E9-7DB-80E+029-7EB-D53 + cheat + description:The bottom of the tiles are always tile three + code:0E9-7DB-80E+039-7EB-D53 + cheat + description:The bottom of the tiles are always tile four + code:0E9-7DB-80E+049-7EB-D53 + cheat + description:The bottom of the tiles are always tile five + code:0E9-7DB-80E+059-7EB-D53 + cheat + description:The bottom of the tiles are always tile six + code:0E9-7DB-80E+069-7EB-D53 + cheat + description:The bottom of the tiles are always tile seven + code:0E9-7DB-80E+079-7EB-D53 + cheat + description:The bottom of the tiles are always tile eight + code:0E9-7DB-80E+089-7EB-D53 + cheat + description:The bottom of the tiles are always tile nine + code:0E9-7DB-80E+099-7EB-D53 + cheat + description:The bottom of the tiles are always tile ten + code:0E9-7DB-80E+0A9-7EB-D53 + cheat + description:The bottom of the tiles are always tile eleven + code:0E9-7DB-80E+0B9-7EB-D53 + cheat + description:The bottom of the tiles are always tile twelve + code:0E9-7DB-80E+0C9-7EB-D53 + cheat + description:The bottom of the tiles are always smart bomb tiles + code:0E9-7DB-80E+0D9-7EB-D53 + cheat + description:The bottom of the tiles are always digger tiles + code:0E9-7DB-80E+0E9-7EB-D53 + cheat + description:The bottom of the tiles are always tile wildcard tiles + code:0E9-7DB-80E+0F9-7EB-D53 + +cartridge sha256:3123e4bcd304d84819c589775db3bf4a2b4fa6d23209b3da691ea7eda6045037 + title:Star Hawk (Europe) + cheat + description:Infinite lives + code:FAA-2CF-4C1 + cheat + description:Impenetrable shield + code:008-C0F-19E + cheat + description:Infinite continues + code:006-92F-F7D + cheat + description:Keep power-ups when you die + code:FAF-15F-4C1 + cheat + description:Start with 8 lives + code:081-C1F-E66 + cheat + description:Start with 10 lives + code:0A1-C1F-E66 + cheat + description:Start with 12 lives + code:0C1-C1F-E66 + +cartridge sha256:2085a11062131fd64c2bc836200a6e203c0bd45909d193c8ad82c0f79f2c025b + title:Star Trek Generations - Beyond the Nexus (USA) (SGB Enhanced) + cheat + description:Almost infinite phasers and shields + code:182-56D-2AA + cheat + description:Infinite attempts in sub game + code:013-D48-805 + cheat + description:Start with very little phasers and shields + code:013-F78-7FB + cheat + description:Start with 1/4 phasers and shields + code:223-F78-7FB + cheat + description:Start with 1/2 phasers and shields + code:3F3-F78-7FB + cheat + description:Start with 3/4 phasers and shields + code:4F3-F78-7FB + +cartridge sha256:9c08d6bdf045668d64934c7cc773bb2353ec15e9dc3e3f5d8ea2e02f2a22be40 + title:Star Trek - The Next Generation (USA, Europe) + cheat + description:Infinite shields + code:FA4-27D-4C1 + cheat + description:Damage isn't repaired + code:001-13D-3BA + cheat + description:Damage repaired immediately + code:001-15D-6E7 + cheat + description:Life support starts at 25% power + code:19E-169-7FB + cheat + description:Life support starts at 50% power + code:32E-169-7FB + cheat + description:Life support starts at 75% power + code:4BE-169-7FB + cheat + description:Warp drive starts at 25% power + code:19E-1A9-7FB + cheat + description:Warp drive starts at 50% power + code:32E-1A9-7FB + cheat + description:Warp drive starts at 75% power + code:4BE-1A9-7FB + cheat + description:Impulse drive starts at 25% power + code:19E-1E9-7FB + cheat + description:Impulse drive starts at 50% power + code:32E-1E9-7FB + cheat + description:Impulse drive starts at 75% power + code:4BE-1E9-7FB + cheat + description:Shields start at 25% power + code:19E-229-7FB + cheat + description:Shields start at 50% power + code:32E-229-7FB + cheat + description:Shields start at 75% power + code:4BE-229-7FB + cheat + description:Phasers start at 25% power + code:19E-269-7FB + cheat + description:Phasers start at 50% power + code:32E-269-7FB + cheat + description:Phasers start at 75% power + code:4BE-269-7FB + cheat + description:Photon Torpedoes start at 25% power + code:19E-2A9-7FB + cheat + description:Photon Torpedoes start at 50% power + code:32E-2A9-7FB + cheat + description:Photon Torpedoes start at 75% power + code:4BE-2A9-7FB + cheat + description:Sensors start at 25% power + code:19E-2E9-7FB + cheat + description:Sensors start at 50% power + code:32E-2E9-7FB + cheat + description:Sensors start at 75% power + code:4BE-2E9-7FB + cheat + description:Transporter starts at 25% power + code:19E-329-7FB + cheat + description:Transporter starts at 50% power + code:32E-329-7FB + cheat + description:Transporter starts at 75% power + code:4BE-329-7FB + +cartridge sha256:9cf6aa2b4d6a4bb877d33bb6131562c9f41deb369d08c5b60266941bb276561f + title:Star Wars (USA) + cheat + description:Infinite energy + code:C9B-5CC-3BE + cheat + description:Infinite lives + code:00B-6AC-195 + cheat + description:Infinite continues + code:FA2-F6E-4C1 + cheat + description:No continues + code:003-A2F-C42 + cheat + description:20 continues + code:143-A2F-C42 + cheat + description:More energy - 1st life only + code:990-B7E-C4A + cheat + description:Start with 1/2 energy on all lives except 1st + code:04C-12C-C4A + cheat + description:Start with 1 life + code:013-B7F-E66 + cheat + description:Start with 6 lives + code:063-B7F-E66 + cheat + description:Start with 9 lives + code:093-B7F-E66 + +cartridge sha256:a62719fa767547a11ac20e0ad5d1fd43b68f92908a5c81dd3aba95f921458c51 + title:Star Wars - The Empire Strikes Back (USA) + cheat + description:Infinite continues + code:00E-A1F-19E + cheat + description:Start with all force abilities in inventory - still need to get force power to activate + code:011-D7F-E6A+001-CFF-5D4 + +cartridge sha256:8730c69cb2aa82260ac07257e0e29d61f598de2f8fa3e65da1d694790fa5db16 + title:Street Fighter II (USA, Europe) (Rev A) (SGB Enhanced) + cheat + description:Player one starts with very little energy + code:013-F89-2AB + cheat + description:Player one starts with 1/4 energy + code:1F3-F89-2AB + cheat + description:Player one starts with 1/2 energy + code:3A3-F89-2AB + cheat + description:Player one starts with 3/4 energy + code:523-F89-2AB + cheat + description:Player one starts with more energy + code:FF3-F89-2AB + cheat + description:Player two starts with very little energy + code:013-FF9-2AB + cheat + description:Player two starts with 1/4 energy + code:1F3-FF9-2AB + cheat + description:Player two starts with 1/2 energy + code:3A3-FF9-2AB + cheat + description:Player two starts with 3/4 energy + code:523-FF9-2AB + cheat + description:Player two starts with more energy + code:FF3-FF9-2AB + cheat + description:Start with seconds on the timer + code:884-619-6E7 + cheat + description:Allows you to select a higher skill level + code:093-85A-F72 + cheat + description:Opponent can't win any normal rounds + code:00B-938-E6D + cheat + description:Fireball doesn't do any damage + code:005-838-B3E + cheat + description:Fireball does more damage + code:405-838-B3E + cheat + description:Fireball kills + code:885-838-B3E + cheat + description:Nobody takes damage from anything but throws/grabs + code:009-249-3B7 + cheat + description:Ryu - Foot sweep doesn't do any damage + code:005-0B8-A2A + cheat + description:Ryu - Foot sweep does more damage + code:405-0B8-A2A + cheat + description:Ryu - Foot sweep kills + code:885-0B8-A2A + cheat + description:Ryu - Crouch punch doesn't do any damage + code:004-F78-A2A + cheat + description:Ryu - Crouch punch does more damage + code:404-F78-A2A + cheat + description:Ryu - Crouch punch kills + code:884-F78-A2A + cheat + description:Ryu - Normal upper cut doesn't do any damage + code:004-A78-A2A + cheat + description:Ryu - Normal upper cut does more damage + code:404-A78-A2A + cheat + description:Ryu - Normal upper cut kills + code:884-A78-A2A + cheat + description:Ryu - Straight punch doesn't do any damage + code:004-CF8-A3A + cheat + description:Ryu - Straight punch does more damage + code:404-CF8-A3A + cheat + description:Ryu - Straight punch kills + code:884-CF8-A3A + cheat + description:Ryu - Standong hack kick doesn't do any damage + code:004-BB8-C42 + cheat + description:Ryu - Standong hack kick does more damage + code:404-BB8-C42 + cheat + description:Ryu - Standong hack kick kills + code:884-BB8-C42 + cheat + description:Ryu - Rolling throw doesn't do any damage + code:005-B58-A22 + cheat + description:Ryu - Rolling throw does more damage + code:405-B58-A22 + cheat + description:Ryu - Rolling throw kills + code:885-B58-A22 + cheat + description:Ryu - Jumping straight up and kicking doesn't do any damage + code:005-338-A2E + cheat + description:Ryu - Jumping straight up and kicking does more damage + code:405-338-A2E + cheat + description:Ryu - Jumping straight up and kicking kills + code:885-338-A2E + cheat + description:Ryu - Standing short kick doesn't do any damage + code:004-D98-C4A + cheat + description:Ryu - Standing short kick does more damage + code:404-D98-C4A + cheat + description:Ryu - Standing short kick kills + code:884-D98-C4A + +cartridge sha256:201aec9eb615f1434100e0db39d6039e3f80670a680b8af9df15915315c170b1 + title:Sumo Fighter (USA) + cheat + description:Infinite energy + code:FAE-C8A-4C1 + cheat + description:At easy or hard level screen, press down three times then A for super hard mode (makes display look weird) + code:092-06F-F7E + cheat + description:Start with 2 energy bars + code:02B-AFA-E66 + cheat + description:Start with 5 energy bars + code:05B-AFA-E66 + cheat + description:Start with 8 energy bars + code:08B-AFA-E66 + cheat + description:Start with 2 lives + code:012-0BF-E62 + cheat + description:Start with 5 lives + code:042-0BF-E62 + cheat + description:Start with 8 lives + code:072-0BF-E62 + +cartridge sha256:79da9658fdd3b92910f0a63ba6c7a45fb680b0e0ebe03ad1ed982d3dc92edae1 + title:Super Battletank - War in the Gulf (USA) + cheat + description:Infinite damage + code:E0B-00C-2A9 + cheat + description:Infinite ammo + code:005-95C-3BE + cheat + description:Infinite fuel + code:C9D-E1D-2A9 + cheat + description:Start with 5 shells + code:05E-42D-2A2 + cheat + description:Start with 99 shells + code:63E-42D-2A2 + cheat + description:Start with 5 laser shots + code:05E-4DD-E6E + cheat + description:Start with 99 laser shots + code:63E-4DD-E6E + cheat + description:Start with 5 smoke shots + code:05E-58D-E6E + cheat + description:Start with 99 smoke shots + code:63E-58D-E6E + cheat + description:Start with 5 bullets + code:05E-63D-B30 + cheat + description:Start with 99 bullets + code:63E-63D-B30 + cheat + description:Start with very little fuel + code:15E-72D-195 + +cartridge sha256:dab87fd694aa1358278b4850371ff1303dea2295b7b7cc14842c969014a73fb1 + title:Super Chase H.Q. (USA, Europe) + cheat + description:Infinite time + code:006-78E-E6E + cheat + description:Infinite turbos + code:007-67E-19E + cheat + description:Turbo boosts last half as long + code:777-47E-081 + cheat + description:Turbo boosts lasts very short + code:157-47E-081 + cheat + description:Turbo boosts lasts forever. Disable to fire a turbo boost then enable while turbo boost is going. + code:007-14E-F79 + cheat + description:Start with lots of points + code:F59-90B-2A1 + cheat + description:Start with 1 turbo boost + code:010-E5A-E66+019-08B-E66 + cheat + description:Start with 2 turbo boosts + code:020-E5A-E66+029-08B-E66 + cheat + description:Start with 5 turbo boosts + code:050-E5A-E66+059-08B-E66 + cheat + description:Start with 9 turbo boosts + code:090-E5A-E66+099-08B-E66 + +cartridge sha256:1a3841dfc6ccf87167d7b1f0ce17f3bbf9fd64445611e249f5902e8824e17483 + title:Super Chinese Land (Japan) + cheat + description:Invincibility (blinking) + code:004-BEE-C4D + cheat + description:Infinite health + code:7C5-0AB-802+125-0BB-3B7 + cheat + description:Infinite lives + code:475-5AA-C4D + +cartridge sha256:49fbd2f61f953d5ef28cab73e357e524c3009ad19fcf30f6a9ee0ae273be41dc + title:Super Mario Land (World) (Rev A) + cheat + description:Enable level select + code:004-D3F-F7F+C34-AAF-A21 + cheat + description:Always have power ball + code:00A-17B-C49 + cheat + description:Infinite time - disable at end of stage + code:008-60A-E6E + cheat + description:Mutli-jump + code:009-C2B-2A1+009-C9B-4C5+009-D8B-80E+009-E4B-C4A+189-AEB-6EA+C9B-75B-809+FA9-E7B-4C1 + cheat + description:Disable music + code:C9C-C39-C49 + +cartridge sha256:470d6c45c9bcf7f0397d00c1ae6de727c63dd471049c8eedbefdc540ceea80b4 + title:Super Mario Land (World) + cheat + description:Enable level select + code:004-D3F-F7F+C34-AAF-A21 + cheat + description:Mutli-jump + code:009-C2B-2A1+009-C9B-4C5+009-D8B-80E+009-E4B-C4A+189-AEB-6EA+C9B-75B-809+FA9-E7B-4C1 + cheat + description:Disable music + code:C9D-BD9-C49 + +cartridge sha256:5450dce1bd0c073964c374b5b5b5729dce8d00f2e807892c34af32b8bce1392e + title:Super Mario Land 2 - 6 Golden Coins (USA, Europe) + cheat + description:Infinite lives + code:001-40C-E6E + cheat + description:Infinite time + code:00D-8DA-E6E + cheat + description:Each defeated enemy worth 2 + code:023-218-E6E + cheat + description:Each defeated enemy worth 5 + code:053-218-E6E + cheat + description:Timer counts down by 2 + code:02D-8DA-E6E + cheat + description:Mushroom turns you into Bunny Mario + code:024-5BC-E6E + cheat + description:Mushroom turns you into Fire Mario + code:034-5BC-E6E + cheat + description:Stay as Super Mario when hit + code:FA1-B9C-4C1 + cheat + description:Stay as Fire or Bunny Mario when hit + code:FA1-C8C-4C1 + cheat + description:Hearts (extra life) worth nothing + code:004-BBC-19A + cheat + description:Play 30 coin game of chance for free + code:004-5F8-2AA + cheat + description:Play 50 coin game of chance for free + code:004-288-A2B + cheat + description:Play 200 coin game of chance for free + code:003-F28-E62 + cheat + description:Play 999 coin game of chance for free + code:003-BB8-C4E+003-BA8-80C + cheat + description:Each coin worth 101 + code:01D-92E-E6A+019-2BA-E6A + cheat + description:Each coin worth 0 + code:009-22A-19A+00D-89E-19A + cheat + description:Can re-enter boss levels + code:181-8DB-4CA + cheat + description:Start new game with 1 life instead of 6 + code:002-41B-F7E + cheat + description:Start new game with 10 lives instead of 6 + code:092-41B-F7E + cheat + description:Start new game with 25 lives instead of 6 + code:242-41B-F7E + cheat + description:Start new game with 50 lives instead of 6 + code:492-41B-F7E + cheat + description:Start new game with 75 lives instead of 6 + code:742-41B-F7E + cheat + description:Start new game with 100 lives instead of 6 + code:992-41B-F7E + +cartridge sha256:91bd1f24827bde4dbb58ead76a8b4e5a507431ec9b6bbc7ef9473b852538a4d5 + title:Super Off Road (USA) + cheat + description:Infinite money + code:FAD-A2B-4C1 + cheat + description:Infinite tires, nitros, etc. when you buy them + code:003-3AD-3BE + cheat + description:Start with 2 credits + code:02B-87F-E66 + cheat + description:Start with 4 credits + code:04B-87F-E66 + cheat + description:Start with 8 credits + code:08B-87F-E66 + +cartridge sha256:f522c83d9dc77825a8bd5933e0877173fcb260fe72c5b032ef38b109250a63e9 + title:Swamp Thing (USA, Europe) + cheat + description:Invincibility + code:C92-85E-A28 + cheat + description:Infinite lives + code:FA3-8FF-4C1 + cheat + description:Infinite environmental meter + code:FAF-CF9-4C1 + cheat + description:Start with half energy + code:205-5AF-E6B + cheat + description:Start with 1/2 environmental meter + code:105-55F-6EA + +cartridge sha256:3e7a15c930db627b82b83f1e2a499436b0419e4d05b85bdfeb2a475e6a07c9b1 + title:Sword of Hope, The (USA) + cheat + description:Infinite HP + code:001-72B-F75 + cheat + description:Start with 11 dexterity points + code:09A-BFD-F7E + cheat + description:12 stamina points + code:09A-C4D-F7E + cheat + description:Shaman is free + code:F04-A0C-6E9 + cheat + description:Forest shop is free + code:F0A-3CC-6E9 + +cartridge sha256:f55e542cc82dc5fbefc0fc5f42e95e882fba7895e73a8ff084ce7aa8408bdd85 + title:T2 - The Arcade Game (USA, Europe) + cheat + description:Infinite energy + code:F0C-9DD-6E9 + cheat + description:Infinite lives + code:F0C-ABD-6E9 + cheat + description:Infinite rockets + code:FA4-B8E-4C1 + cheat + description:Infinite continues + code:FAD-5CE-4C1 + cheat + description:Start with 2 lives + code:023-46F-F7E + cheat + description:Start with 4 lives + code:043-46F-F7E + cheat + description:Start with 8 lives + code:083-46F-F7E + +cartridge sha256:596787d9f1dfeef0151b20ce330ef78220e041d0a360b34dea75ce21c7cbb889 + title:Taz-Mania (USA, Europe) + cheat + description:Invincibility + code:003-658-E69 + cheat + description:Infinite spins + code:FAC-519-4C1 + cheat + description:Infinite hearts + code:FA7-3CC-4C1 + cheat + description:Infinite time + code:FA6-AA8-4C1 + cheat + description:Infinite credits + code:FAA-48D-4C1 + cheat + description:Don't flash after getting hit + code:00A-969-E68 + cheat + description:Don't flash as long after getting hit + code:11A-969-E68 + cheat + description:Flash longer after getting hit + code:F1A-969-E68 + cheat + description:Start with 1 heart - 1st life + code:017-6EF-E66 + cheat + description:Start with 5 hearts - 1st life + code:057-6EF-E66 + cheat + description:Start with 10 hearts - 1st life + code:0A7-6EF-E66 + cheat + description:Start timer at 58 seconds + code:3E8-408-80E+058-418-4C2 + cheat + description:Start timer at 1 minute 48 seconds + code:3E8-408-80E+0A8-418-4C2 + +cartridge sha256:1f3c9ff627b0445e57a7425bc433c0476a0eeafe25ea5c6522b102d1ef8f875e + title:Tecmo Bowl (USA) + cheat + description:Infinite time + code:00D-C9A-3BE + cheat + description:Have 49 downs + code:494-D6B-F7A + cheat + description:Have 5 downs + code:054-D6B-F7A + cheat + description:8 minutes 30 seconds per quarter + code:084-EFB-E6E + cheat + description:6 minutes 30 seconds per quarter + code:064-EFB-E6E + cheat + description:1 minutes 30 seconds per quarter + code:014-EFB-E6E + +cartridge sha256:cdcb6ba23ea2c32a2af47abb267d8bd065a8bc10777b435de6a9be421e5bf919 + title:Tennis (World) + cheat + description:Neither player scores points - disable to score + code:001-DAD-3BA + cheat + description:1 game needed to win set + code:010-9CD-F76 + cheat + description:2 games needed to win set + code:020-9CD-F76 + cheat + description:3 games needed to win set + code:030-9CD-F76 + cheat + description:4 games needed to win set + code:040-9CD-F76 + cheat + description:1st point takes you to 40 points + code:011-9AD-E66 + cheat + description:2nd point takes you to 40 points + code:021-9AD-E66 + cheat + description:Neither player can win game + code:000-99D-3BA+E00-74D-6E5+E00-7ED-6E5 + +cartridge sha256:5fa11359e8147b295bebd1e5631c7b96908c649d9d33fdc45a2dd3de8d69ca73 + title:Terminator 2 - Judgment Day (USA, Europe) + cheat + description:Almost infinite energy + code:C95-00E-4C1 + cheat + description:Infinite time in reprogramming stage + code:001-03B-19E + cheat + description:20 shots kill end of level 1 boss + code:148-54B-4CA + cheat + description:10 shots kill end of level 1 boss + code:0A8-54B-4CA + cheat + description:5 shots kill end of level 1 boss + code:058-54B-4CA + cheat + description:Start with 1/2 energy + code:70E-59D-6E9 + +cartridge sha256:0d6535aef23969c7e5af2b077acaddb4a445b3d0df7bf34c8acef07b51b015c3 + title:Tetris (World) (Rev A) + cheat + description:Keep stack displayed while paused + code:CEC-30E-C45 + cheat + description:Keep current and next pieces displayed while paused + code:D9C-53E-D5D + cheat + description:Only piece 1 will appear + code:000-63D-6E9+3E0-64D-5D0+000-65D-087 + cheat + description:Only piece 2 will appear + code:000-63D-6E9+3E0-64D-5D0+040-65D-087 + cheat + description:Only piece 3 will appear + code:000-63D-6E9+3E0-64D-5D0+080-65D-087 + cheat + description:Only piece 4 will appear + code:000-63D-6E9+3E0-64D-5D0+0C0-65D-087 + cheat + description:Only piece 5 will appear + code:000-63D-6E9+3E0-64D-5D0+100-65D-087 + cheat + description:Only piece 6 will appear + code:000-63D-6E9+3E0-64D-5D0+140-65D-087 + cheat + description:Only piece 7 will appear + code:000-63D-6E9+3E0-64D-5D0+180-65D-087 + +cartridge sha256:d349dc93423c6abcd775d3b6a8797df715a44a42ec837afb21bf17ae43b40a9e + title:Tetris DX (World) (SGB Enhanced) + cheat + description:Score increases a lot + code:1F3-C9A-F70 + cheat + description:Swap over next shape to current shape by pressing A + code:C37-C5A-081+B67-C6A-E60+587-C7A-5D4 + cheat + description:Swap over next shape to current shape by pressing B + code:C38-1EA-081+B68-1FA-E60+588-20A-5D4 + cheat + description:Swap over next shape to current shape by pressing select + code:188-76A-081+3E8-77A-F74 + +cartridge sha256:771d24adf7dd11ff166fc43d3f2be66dd7a24251b8920e813956c62514813051 + title:Tetris 2 (USA) + cheat + description:No next piece screen + code:C98-E9A-081 + cheat + description:Blocks come down fast + code:10D-649-F71+00D-629-081+3ED-639-B30 + cheat + description:Blocks come down very fast + code:70D-649-F71+00D-629-081+3ED-639-B30 + cheat + description:Blocks come down super fast + code:20D-649-F71+00D-629-081+3ED-639-B30 + cheat + description:Can select round above 30 on options screen + code:00A-4BA-A29 + cheat + description:In versus mode, no blocks added to top of screen + code:FA8-CB8-4C1 + +cartridge sha256:fe2f3a9c8af3702b53398fea579951634effbeafaea10865aac8b07d7458e9b1 + title:Tiny Toon Adventures 2 (Japan) + cheat + description:Invincibility + code:C3C-DAD-E61 + cheat + description:Infinite energy + code:00D-5CD-19E + cheat + description:Infinite time + code:006-14B-19E + cheat + description:Infinite lives + code:00A-5ED-E6E + cheat + description:One hit and you die + code:00D-53D-679 + cheat + description:Don't flash as long after getting hit + code:3FD-53D-679 + cheat + description:Start with 1 heart + code:029-66E-F7A + cheat + description:Start with 2 hearts + code:039-66E-F7A + cheat + description:Start with 1 life + code:00E-1E9-E62 + cheat + description:Start with 5 lives + code:04E-1E9-E62 + cheat + description:Start with 10 lives + code:09E-1E9-E62 + cheat + description:Start with mega points + code:00E-229-5D4 + cheat + description:Start with 100 seconds on the clock + code:01E-319-F7E + cheat + description:Start with 300 seconds on the clock + code:03E-319-F7E + cheat + description:Start with 700 seconds on the clock + code:07E-319-F7E + cheat + description:Start with 900 seconds on the clock + code:09E-319-F7E + +cartridge sha256:4d078174031509ca7b63c237e176e9f5c0aed88b42352ad23aee98a777d3a0d7 + title:Titus the Fox to Marrakech and Back (USA, Europe) + cheat + description:Infinite energy until level 3 + code:00E-7D9-3BE + cheat + description:Infinite energy from level 3 on + code:002-739-3BE + cheat + description:Infinite lives + code:009-6A9-3BE + cheat + description:Start 1st life with 1 energy unit + code:013-D0A-F7E + cheat + description:Start 1st life with 9 energy units + code:093-D0A-F7E + cheat + description:Start with 1 energy unit after 1st life + code:011-CFD-F7E + cheat + description:Start with 9 energy units after 1st life + code:091-CFD-F7E + cheat + description:Start 1st level with 100-pt. bonus + code:643-DCA-E6A + cheat + description:Start 1st level with 250-pt. bonus + code:FA3-DCA-E6A + cheat + description:Start with 1 life + code:013-D5A-E66 + cheat + description:Start with 6 lives + code:063-D5A-E66 + cheat + description:Start with 9 lives + code:093-D5A-E66 + cheat + description:Start on level 1, part 2 + code:003-BAF-5D4 + +cartridge sha256:597f70c8d600427fee6f3a3714115bad30b24402dd830c36dc010a7b3a92a7a3 + title:Tom & Jerry (USA, Europe) + cheat + description:Infinite lives + code:008-54D-B3D + cheat + description:Infinite balls once collected + code:FA6-84B-4C1 + cheat + description:Infinite energy (may have to die once first) + code:00D-47D-3BA + cheat + description:Infinite time + code:FAC-3FE-4C1+FAC-43E-4C1 + cheat + description:Every time you collect one cheese you get 11 (can't go over 100) + code:110-67B-E6E + cheat + description:Start with 1 life + code:01F-7BB-E66 + cheat + description:Start with 5 lives + code:05F-7BB-E66 + +cartridge sha256:bcd52c83f3662165baaeff2527fd221c04b734214d5dacb8cdda6fbcb95fbc3b + title:Tom and Jerry - Frantic Antics! (USA, Europe) + cheat + description:Infinite lives + code:01E-39E-A25 + cheat + description:Infinite lives + code:00C-E4B-3BE + cheat + description:Infinite time + code:001-43C-E6E+001-51C-E6E + cheat + description:Don't flash after getting hit + code:013-338-08B + cheat + description:Flash longer after getting hit + code:FA3-338-08B + cheat + description:Start with 1 life + code:019-0CC-E66 + cheat + description:Start with 5 lives + code:059-0CC-E66 + cheat + description:Start with 10 lives + code:0A9-0CC-E66 + cheat + description:Start with 1 minutes on the timer + code:010-DEC-F7E + cheat + description:Start with 10 minutes on the timer + code:0A0-DEC-F7E + cheat + description:Start with 15 minutes on the timer - ignore counter + code:0F0-DEC-F7E + +cartridge sha256:bb2f56c5035b47183c55b197bc380ea02df00dd733ce732d062f7c7695bd330f + title:Top Gun - Guts & Glory (USA, Europe) + cheat + description:Infinite missiles + code:FA4-249-4C1 + cheat + description:Infinite lives + code:008-599-F79 + cheat + description:Start with 1 life (do not alter mission on the first menu screen) + code:01B-E4D-E66 + cheat + description:Start with 5 lives (do not alter mission on the first menu screen) + code:05B-E4D-E66 + cheat + description:Start with 10 lives (do not alter mission on the first menu screen) + code:0AB-E4D-E66 + cheat + description:Start on mission 10 (do not alter mission on the first menu screen) + code:004-859-4C1+3E4-869-80C+0A4-879-F7D + +cartridge sha256:13a6106b5548261764b0f0d676b07265e6ed37b4cf2f85fc763b05dde749eb64 + title:Total Carnage (USA, Europe) + cheat + description:Infinite grenades + code:FA2-28D-4C1 + cheat + description:Infinite lives + code:001-ADD-19E + cheat + description:Start with very little energy after 1st life + code:021-B1D-F72 + cheat + description:Start with mega energy after 1st life + code:991-B1D-F72 + cheat + description:Don't take damage from some enemies after getting hit + code:003-55E-19E + cheat + description:Start with very little energy-1st life + code:020-54B-F72 + cheat + description:Start with mega energy-1st life + code:990-54B-F72 + cheat + description:Start with 1 life + code:000-4FB-E66 + cheat + description:Start with 9 lives + code:080-4FB-E66 + cheat + description:Start with 15 lives + code:0F0-4FB-E66 + cheat + description:Start with 33 grenades + code:030-5FB-E6A + +cartridge sha256:eae3b192006eff607dffdae3d7720af579f85335be81e6cacb55276bfc32424c + title:Track & Field (USA, Europe) + cheat + description:Always have 100% power + code:3E7-7FD-4CA+007-80D-E6E + cheat + description:Max angle on long jump + code:45D-999-E68 + cheat + description:Max angle on javelin + code:45A-1EA-E68 + cheat + description:Max angle on triple jump + code:454-D1A-E68 + +cartridge sha256:3990c42543e74387c30ac935eb45067e291b4a5e93702d5520acd0e91d14f34f + title:Tumble Pop (USA, Europe) + cheat + description:Infinite lives + code:FA5-BCD-4C1 + cheat + description:Only have 2 minutes to complete each screen + code:028-8AE-E66 + cheat + description:Only have 5 minutes to complete each screen + code:058-8AE-E66 + cheat + description:Only have 10 minutes to complete each screen + code:0A8-8AE-E66 + cheat + description:Start across river from original position + code:058-17E-E6A + cheat + description:Start at island castle + code:FF8-17E-E6A + cheat + description:Hold enemies inside gun as long as you want + code:00E-68D-3BE + cheat + description:Start with 1 life + code:008-1CE-E66 + cheat + description:Start with 6 lives + code:058-1CE-E66 + cheat + description:Start with 9 lives + code:088-1CE-E66 + +cartridge sha256:954ed263a5133c608636af442c4c0ade7f9b7dfdc768e7bfbf31d2528a8d7796 + title:Turn and Burn (USA) + cheat + description:Infinite missiles + code:00E-1CD-3BE + cheat + description:Gun doesn't overheat + code:001-51C-F7A + cheat + description:Start with more Aim-54 missiles + code:7C2-99E-08F + cheat + description:Start with more Aim-9 missiles + code:7C2-8BE-08F + +cartridge sha256:9008df8d950b4e6966b38218e43bc3baf9bad91ef44b271b558aee6f38c993d7 + title:Ultima - Runes of Virtue (USA) + cheat + description:Infinite energy + code:FA5-F3F-4C1+FA4-00C-4C1 + cheat + description:Infinite money + code:FAB-5BF-4C1 + cheat + description:Start with dexterity of 10 - Shamino codes only - can't use with Journey Onward option + code:106-2B8-B3E + cheat + description:Start with dexterity of 30 - Shamino codes only - can't use with Journey Onward option + code:306-2B8-B3E + cheat + description:Start with dexterity of 50 - Shamino codes only - can't use with Journey Onward option + code:506-2B8-B3E + cheat + description:Start with strength of 10 - Shamino codes only - can't use with Journey Onward option + code:106-2C8-B3E + cheat + description:Start with strength of 30 - Shamino codes only - can't use with Journey Onward option + code:306-2C8-B3E + cheat + description:Start with strength of 50 - Shamino codes only - can't use with Journey Onward option + code:506-2CA-B3E + cheat + description:Start with IQ of 10 - Shamino codes only - can't use with Journey Onward option + code:106-2F8-B3E + cheat + description:Start with IQ of 30 - Shamino codes only - can't use with Journey Onward option + code:306-2F8-B3E + cheat + description:Start with IQ of 50 - Shamino codes only - can't use with Journey Onward option + code:506-2F8-B3E + cheat + description:Start with 15 coins - Shamino codes only - can't use with Journey Onward option + code:155-658-2AA + cheat + description:Start with 40 coins - Shamino codes only - can't use with Journey Onward option + code:405-658-2AA + cheat + description:Start with 60 coins - Shamino codes only - can't use with Journey Onward option + code:605-658-2AA + cheat + description:No energy replacement - Shamino codes only - can't use with Journey Onward option + code:FAC-0AF-4C1 + +cartridge sha256:850a429b64b7ebcb8034da2c25789dff631d64682b1ce65f8de346c9744ae31e + title:Universal Soldier (USA, Europe) + cheat + description:Infinite energy + code:008-7AC-3BE + cheat + description:Infinite time + code:00A-5AF-3BE + cheat + description:Infinite lives + code:C93-EEF-E69 + cheat + description:Fewer enemies on each level + code:00C-50E-3BA+00C-4BE-3BE + cheat + description:Start with 5 lives + code:055-D1E-E66 + cheat + description:Start with 7 lives + code:075-D1E-E66 + cheat + description:Start with 9 lives + code:095-D1E-E66 + cheat + description:Start with 5 power lines + code:056-ACE-E66 + cheat + description:Start with 7 power lines + code:076-ACE-E66 + cheat + description:Start with 9 power lines + code:096-ACE-E66 + +cartridge sha256:1af2d4b29552fb2cf141955e1d77f8dd99e856b1f04fbff5240d5a1c3c2c41bf + title:Wario Blast Featuring Bomberman! (USA, Europe) (SGB Enhanced) + cheat + description:Infinite time + code:00A-5BF-3B7 + cheat + description:Collect up to 8 extra bomb power-ups + code:083-F1A-F7A + cheat + description:Extra bomb power-ups don't do anything + code:003-EFA-3B7 + cheat + description:Explosion expanders don't do anything + code:003-D7A-3B7 + cheat + description:Start with 300 seconds + code:03F-87E-E6E + cheat + description:Start with 4 extra bomb power-ups + code:046-C7D-E6E + cheat + description:Start with 4 explosion expander + code:046-CBD-E6A + cheat + description:Start on round 3-3 + code:210-3BB-4C1+000-13B-5D4 + cheat + description:Start on round 3-Boss + code:210-3BB-4C1+3C0-13B-5D4 + +cartridge sha256:ac1682f17abcf590311a233289ee325214c2d71ab3a5aa175004002d85075e56 + title:Wario Land - Super Mario Land 3 (World) + cheat + description:Don't lose current power-up when you get hit or get a new power-up (switchable) + code:FAD-63F-4C1 + cheat + description:Most enemies and obstacles are invisible + code:003-AAB-E62+C96-C0C-4C1 + cheat + description:Multi-jump + code:C41-8EA-E61+C41-93A-E61+181-96A-C45+111-97A-F77 + cheat + description:Get 10 hearts for killing an enemy + code:103-E4F-E6E + cheat + description:Get 25 hearts for killing an enemy + code:253-E4F-E6E + cheat + description:Get 50 hearts for killing an enemy + code:503-E4F-E6E + cheat + description:Get 99 hearts for killing an enemy + code:993-E4F-E6E + cheat + description:Start as Small Wario + code:00B-7E8-E6E + cheat + description:Start as Bull Wario + code:02B-7E8-E6E + cheat + description:Start as Jet Wario + code:03B-7E8-E6E + cheat + description:Start as Dragon Wario + code:04B-7E8-E6E + cheat + description:Start with 10 hearts + code:10B-7C8-E6A + cheat + description:Start with 25 hearts + code:25B-7C8-E6A + cheat + description:Start with 50 hearts + code:50B-7C8-E6A + cheat + description:Start with 99 hearts + code:99B-7C8-E6A + cheat + description:Start with 10 coins + code:10B-7B8-E6A + cheat + description:Start with 25 coins + code:25B-7B8-E6A + cheat + description:Start with 50 coins + code:50B-7B8-E6A + cheat + description:Start with 99 coins + code:99B-7B8-E6A + cheat + description:Start with 10 lives + code:10B-7D8-F7E + cheat + description:Start with 25 lives + code:25B-7D8-F7E + cheat + description:Start with 50 lives + code:50B-7D8-F7E + cheat + description:Start with 99 lives + code:99B-7D8-F7E + cheat + description:Start on course 26 + code:01B-7F8-E6A + cheat + description:No turbo boost + code:002-40E-19A + cheat + description:Infinite turbo boost + code:002-CAE-19E + cheat + description:No lap timer + code:003-B7A-6E2 + cheat + description:Start with 800cc bike + code:3E9-65B-6EA+029-66B-E66+009-67B-5D4 + cheat + description:Start with 650cc bike + code:3E9-65B-6EA+019-66B-E66+009-67B-5D4 + +cartridge sha256:a3bd35fb1d2466868b5308a45e8ad3844925bd5dfa819b27ff67d0391b8e3511 + title:WCW Main Event (USA, Europe) + cheat + description:Infinite time + code:003-3ED-E6E + cheat + description:One hit kills + code:186-06E-2AA+AF6-05E-A28 + cheat + description:Never regain energy + code:C95-D9E-3BA + cheat + description:Computer does massive damage + code:096-3EE-E6E + cheat + description:Faster timer + code:023-3ED-E6E + +cartridge sha256:db8029c84c99c1bff1724656d0887636497986fac02892f4d4334c60f646c84f + title:Wild Snake (USA) (SGB Enhanced) + cheat + description:Infinite time in King Cobra mode + code:FAB-1EF-4C1 + cheat + description:All snakes are shorter + code:3E2-7ED-2AA+032-7FD-3BD + cheat + description:Only plain yellow snakes fall + code:3E3-15D-08F+013-16D-7F4 + cheat + description:Only zig-zag snakes fall + code:3E3-15D-08F+023-16D-7F4 + cheat + description:Only dark dotted snakes fall + code:3E3-15D-08F+033-16D-7F4 + cheat + description:Only light dotted snakes fall + code:3E3-15D-08F+043-16D-7F4 + cheat + description:Only dark striped snakes fall + code:3E3-15D-08F+053-16D-7F4 + cheat + description:Only light striped snakes fall + code:3E3-15D-08F+063-16D-7F4 + cheat + description:Only vertically striped snakes fall + code:3E3-15D-08F+073-16D-7F4 + cheat + description:Only checkered snake snakes fall + code:3E3-15D-08F+083-16D-7F4 + cheat + description:Only skeleton snakes fall + code:3E3-15D-08F+0A3-16D-7F4 + cheat + description:Only temporarily invisible snakes fall + code:3E3-15D-08F+0B3-16D-7F4 + cheat + description:Only dark snakes fall + code:3E3-15D-08F+0C3-16D-7F4 + cheat + description:Only wild snakes fall + code:3E3-15D-08F+0D3-16D-7F4 + cheat + description:Only king cobra snakes fall + code:3E3-15D-08F+0E3-16D.-7F4 + cheat + description:Collect 1 snake in King Cobra mode and finish level + code:3E6-DFD-081+3E6-E1D-C49+306-E2D-19A + cheat + description:Snakes fall very fast + code:3E5-53B-081+015-54B-C47+005-55B-F71 + cheat + description:Snakes fall extremely fast + code:3E5-53B-081+005-54B-C47+005-55B-F71 + cheat + description:Snakes fall slower + code:3E5-53B-081+055-54B-C47+005-55B-F71 + cheat + description:Snakes fall very slow + code:3E5-53B-081+1F5-54B-C47+005-55B-F71 + cheat + description:Snakes fall extremely slow + code:3E5-53B-081+AF5-54B-C47+005-55B-F71 + +cartridge sha256:b396d2a15563b6144630d5ec5f0a8a2928a4b289ca215e6cc581df7a5fe295ff + title:WordZap (USA) + cheat + description:Infinite hints + code:008-70F-3BE + cheat + description:Start with only 1 hint + code:01B-C9E-F7A + cheat + description:Start with 5 hints + code:05B-C9E-F7A + cheat + description:Start with 9 hints + code:09B-C9E-F7A + cheat + description:Start with 1 chance + code:01B-CEE-E66 + cheat + description:Start with 9 chances + code:09B-CEE-E66 + +cartridge sha256:439854d8d2ec85bffb171efe3ec0d6ba98fed2443b26053340daaf8190611859 + title:World Bowling (USA) + cheat + description:Always bowl at full power + code:3E6-94B-F71+FF6-95B-C4E + cheat + description:Get a spare even if you miss + code:3E3-44A-08F+0A3-45A-A28 + +cartridge sha256:246d48cb2a6ed53a7cf78d94fc219762aaaea0111467a5fcf415ca76f9170124 + title:World Circuit Series (USA) + cheat + description:No loss of speed on course you take your finger from acceleration button + code:00C-A0E-19E + cheat + description:No loss of speed when you leave course-except hitting walls + code:00A-E2E-3BE + cheat + description:No qualifying timer + code:003-84F-3BE+C93-85F-E69 + +cartridge sha256:0ba3d3b9be8c615bd29956887584aff9446a88fb2606bfb8ccc75907164c4cf9 + title:WWF King of the Ring (USA, Europe) + cheat + description:No out of ring timer + code:00C-0FD-E6E + +cartridge sha256:3843f2cdb0746ff0cf7dc97e1aab4fc6a15219e7ac8e1970ead475a835c57aea + title:Xenon 2 - Megablast (USA, Europe) + cheat + description:Infinite energy + code:FA4-16D-4C1 + cheat + description:Infinite lives + code:FA2-EBF-4C1 + cheat + description:Purchases at shop are free + code:C96-DBC-6EE + cheat + description:When you die you get an awesome ship (for a while) + code:002-F4F-5D4 + cheat + description:Start with very little energy + code:013-08F-A22 + cheat + description:Start with 1/3 energy + code:053-08F-A22 + cheat + description:Start with 1/2 energy + code:093-08F-A22 + cheat + description:Start with 2,222,222 points + code:002-04F-5D4 + cheat + description:Start with 1 life + code:011-75C-F7E + cheat + description:Start with 5 lives + code:051-75C-F7E + cheat + description:Start with 10 lives + code:0A1-75C-F7E + +cartridge sha256:98fb28e23fa2bdb969317544bf0fd5c24fb377134cac12897b29889bc67f6ca6 + title:Yogi Bear in Yogi Bear's Goldrush (USA) + cheat + description:Power-up after almost every shot + code:007-CB8-4CA + +cartridge sha256:a41d3ab34e91fccdf6b4e3a203dbf606d1097b702039fdf2f252cb18c4c9f925 + title:Yoshi (USA) + cheat + description:At random intervals, 1 block comes down instead of 2 + code:003-BBE-193 + cheat + description:When setup screen appears, go to level select, push right once to start on level 6 + code:3EC-70D-081+06C-71D-2AC+22C-72D-F71 + cheat + description:When setup screen appears, go to level select, push right once to start on level 8 + code:3EC-70D-081+08C-71D-2AC+22C-72D-F71 + cheat + description:No timer for game B + code:00C-71B-3BA + +cartridge sha256:1f6a79c3a548718eea5cf530f30d67f8fd76ee9693cd2da164caef36d310a501 + title:Zen - Intergalactic Ninja (USA) + cheat + description:Infinite lives + code:FA9-6DE-4C1 + cheat + description:Infinite energy against bullets and most enemies + code:FA3-36B-4C1+FA2-A4B-4C1 + cheat + description:Instant staff power-up (hold B) + code:01A-3ED-F7E + cheat + description:No energy loss against fire + code:FA1-B1A-4C1 + cheat + description:No energy loss against hang-on enemies + code:FAF-DAD-4C1 + cheat + description:Start lives with 1/2 energy + code:051-668-C42 + cheat + description:Start each life with 7 energy points + code:071-668-C42 + cheat + description:Start with 1 life + code:015-91F-E66 + cheat + description:Start with 5 lives + code:055-91F-E66 + cheat + description:Start with 10 lives + code:0A5-91F-E66 + diff --git a/gameboy/Makefile b/gameboy/Makefile new file mode 100755 index 00000000..977c1050 --- /dev/null +++ b/gameboy/Makefile @@ -0,0 +1,16 @@ +gameboy_objects := gameboy-interface gameboy-system gameboy-scheduler +gameboy_objects += gameboy-memory gameboy-cartridge +gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd +gameboy_objects += gameboy-cheat gameboy-video +objects += $(gameboy_objects) + +obj/gameboy-interface.o: $(gameboy)/interface/interface.cpp $(call rwildcard,$(gameboy)/interface/) +obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/) +obj/gameboy-scheduler.o: $(gameboy)/scheduler/scheduler.cpp $(call rwildcard,$(gameboy)/scheduler/) +obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/) +obj/gameboy-memory.o: $(gameboy)/memory/memory.cpp $(call rwildcard,$(gameboy)/memory/) +obj/gameboy-cpu.o: $(gameboy)/cpu/cpu.cpp $(call rwildcard,$(gameboy)/cpu/) +obj/gameboy-apu.o: $(gameboy)/apu/apu.cpp $(call rwildcard,$(gameboy)/apu/) +obj/gameboy-lcd.o: $(gameboy)/lcd/lcd.cpp $(call rwildcard,$(gameboy)/lcd/) +obj/gameboy-cheat.o: $(gameboy)/cheat/cheat.cpp $(call rwildcard,$(gameboy)/cheat/) +obj/gameboy-video.o: $(gameboy)/video/video.cpp $(call rwildcard,$(gameboy)/video/) diff --git a/gameboy/apu/apu.cpp b/gameboy/apu/apu.cpp new file mode 100755 index 00000000..be3a4e77 --- /dev/null +++ b/gameboy/apu/apu.cpp @@ -0,0 +1,107 @@ +#include + +#define APU_CPP +namespace GameBoy { + +#include "square1/square1.cpp" +#include "square2/square2.cpp" +#include "wave/wave.cpp" +#include "noise/noise.cpp" +#include "master/master.cpp" +#include "serialization.cpp" +APU apu; + +void APU::Main() { + apu.main(); +} + +void APU::main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(sequencer_base == 0) { //512hz + if(sequencer_step == 0 || sequencer_step == 2 || sequencer_step == 4 || sequencer_step == 6) { //256hz + square1.clock_length(); + square2.clock_length(); + wave.clock_length(); + noise.clock_length(); + } + if(sequencer_step == 2 || sequencer_step == 6) { //128hz + square1.clock_sweep(); + } + if(sequencer_step == 7) { //64hz + square1.clock_envelope(); + square2.clock_envelope(); + noise.clock_envelope(); + } + sequencer_step++; + } + sequencer_base++; + + square1.run(); + square2.run(); + wave.run(); + noise.run(); + master.run(); + + interface->audioSample(master.center, master.left, master.right); + + clock += 1 * cpu.frequency; + if(clock >= 0) co_switch(scheduler.active_thread = cpu.thread); + } +} + +void APU::power() { + create(Main, 4 * 1024 * 1024); + for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this; + + for(auto &n : mmio_data) n = 0x00; + sequencer_base = 0; + sequencer_step = 0; + + square1.power(); + square2.power(); + wave.power(); + noise.power(); + master.power(); +} + +uint8 APU::mmio_read(uint16 addr) { + static const uint8 table[48] = { + 0x80, 0x3f, 0x00, 0xff, 0xbf, //square1 + 0xff, 0x3f, 0x00, 0xff, 0xbf, //square2 + 0x7f, 0xff, 0x9f, 0xff, 0xbf, //wave + 0xff, 0xff, 0x00, 0x00, 0xbf, //noise + 0x00, 0x00, 0x70, //master + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //unmapped + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern + }; + + if(addr == 0xff26) { + uint8 data = master.enable << 7; + if(square1.enable) data |= 0x01; + if(square2.enable) data |= 0x02; + if( wave.enable) data |= 0x04; + if( noise.enable) data |= 0x08; + return data | table[addr - 0xff10]; + } + + if(addr >= 0xff10 && addr <= 0xff3f) return mmio_data[addr - 0xff10] | table[addr - 0xff10]; + return 0xff; +} + +void APU::mmio_write(uint16 addr, uint8 data) { + if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data; + + if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data); + if(addr >= 0xff15 && addr <= 0xff19) return square2.write (addr - 0xff15, data); + if(addr >= 0xff1a && addr <= 0xff1e) return wave.write (addr - 0xff1a, data); + if(addr >= 0xff1f && addr <= 0xff23) return noise.write (addr - 0xff1f, data); + if(addr >= 0xff24 && addr <= 0xff26) return master.write (addr - 0xff24, data); + if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data); +} + +} diff --git a/gameboy/apu/apu.hpp b/gameboy/apu/apu.hpp new file mode 100755 index 00000000..7218415c --- /dev/null +++ b/gameboy/apu/apu.hpp @@ -0,0 +1,28 @@ +struct APU : Processor, MMIO { + #include "square1/square1.hpp" + #include "square2/square2.hpp" + #include "wave/wave.hpp" + #include "noise/noise.hpp" + #include "master/master.hpp" + + uint8 mmio_data[48]; + uint13 sequencer_base; + uint3 sequencer_step; + + Square1 square1; + Square2 square2; + Wave wave; + Noise noise; + Master master; + + static void Main(); + void main(); + void power(); + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + + void serialize(serializer&); +}; + +extern APU apu; diff --git a/gameboy/apu/master/master.cpp b/gameboy/apu/master/master.cpp new file mode 100755 index 00000000..bd0a247e --- /dev/null +++ b/gameboy/apu/master/master.cpp @@ -0,0 +1,119 @@ +#ifdef APU_CPP + +void APU::Master::run() { + if(enable == false) { + center = 0; + left = 0; + right = 0; + return; + } + + signed sample = 0; + sample += apu.square1.output; + sample += apu.square2.output; + sample += apu.wave.output; + sample += apu.noise.output; + center = (sample * 512) - 16384; + + sample = 0; + if(channel1_left_enable) sample += apu.square1.output; + if(channel2_left_enable) sample += apu.square2.output; + if(channel3_left_enable) sample += apu.wave.output; + if(channel4_left_enable) sample += apu.noise.output; + left = (sample * 512) - 16384; + + switch(left_volume) { + case 0: left >>= 3; break; // 12.5% + case 1: left >>= 2; break; // 25.0% + case 2: left = (left >> 2) + (left >> 3); break; // 37.5% + case 3: left >>= 1; break; // 50.0% + case 4: left = (left >> 1) + (left >> 3); break; // 62.5% + case 5: left -= (left >> 2); break; // 75.0% + case 6: left -= (left >> 3); break; // 87.5% + //case 7: break; //100.0% + } + + sample = 0; + if(channel1_right_enable) sample += apu.square1.output; + if(channel2_right_enable) sample += apu.square2.output; + if(channel3_right_enable) sample += apu.wave.output; + if(channel4_right_enable) sample += apu.noise.output; + right = (sample * 512) - 16384; + + switch(right_volume) { + case 0: right >>= 3; break; // 12.5% + case 1: right >>= 2; break; // 25.0% + case 2: right = (right >> 2) + (right >> 3); break; // 37.5% + case 3: right >>= 1; break; // 50.0% + case 4: right = (right >> 1) + (right >> 3); break; // 62.5% + case 5: right -= (right >> 2); break; // 75.0% + case 6: right -= (right >> 3); break; // 87.5% + //case 7: break; //100.0% + } +} + +void APU::Master::write(unsigned r, uint8 data) { + if(r == 0) { //$ff24 NR50 + left_in_enable = data & 0x80; + left_volume = (data >> 4) & 7; + right_in_enable = data & 0x08; + right_volume = (data >> 0) & 7; + } + + if(r == 1) { //$ff25 NR51 + channel4_left_enable = data & 0x80; + channel3_left_enable = data & 0x40; + channel2_left_enable = data & 0x20; + channel1_left_enable = data & 0x10; + channel4_right_enable = data & 0x08; + channel3_right_enable = data & 0x04; + channel2_right_enable = data & 0x02; + channel1_right_enable = data & 0x01; + } + + if(r == 2) { //$ff26 NR52 + enable = data & 0x80; + } +} + +void APU::Master::power() { + left_in_enable = 0; + left_volume = 0; + right_in_enable = 0; + right_volume = 0; + channel4_left_enable = 0; + channel3_left_enable = 0; + channel2_left_enable = 0; + channel1_left_enable = 0; + channel4_right_enable = 0; + channel3_right_enable = 0; + channel2_right_enable = 0; + channel1_right_enable = 0; + enable = 0; + + center = 0; + left = 0; + right = 0; +} + +void APU::Master::serialize(serializer &s) { + s.integer(left_in_enable); + s.integer(left_volume); + s.integer(right_in_enable); + s.integer(right_volume); + s.integer(channel4_left_enable); + s.integer(channel3_left_enable); + s.integer(channel2_left_enable); + s.integer(channel1_left_enable); + s.integer(channel4_right_enable); + s.integer(channel3_right_enable); + s.integer(channel2_right_enable); + s.integer(channel1_right_enable); + s.integer(enable); + + s.integer(center); + s.integer(left); + s.integer(right); +} + +#endif diff --git a/gameboy/apu/master/master.hpp b/gameboy/apu/master/master.hpp new file mode 100755 index 00000000..31a1e9f0 --- /dev/null +++ b/gameboy/apu/master/master.hpp @@ -0,0 +1,24 @@ +struct Master { + bool left_in_enable; + uint3 left_volume; + bool right_in_enable; + uint3 right_volume; + bool channel4_left_enable; + bool channel3_left_enable; + bool channel2_left_enable; + bool channel1_left_enable; + bool channel4_right_enable; + bool channel3_right_enable; + bool channel2_right_enable; + bool channel1_right_enable; + bool enable; + + int16 center; + int16 left; + int16 right; + + void run(); + void write(unsigned r, uint8 data); + void power(); + void serialize(serializer&); +}; diff --git a/gameboy/apu/noise/noise.cpp b/gameboy/apu/noise/noise.cpp new file mode 100755 index 00000000..c0def117 --- /dev/null +++ b/gameboy/apu/noise/noise.cpp @@ -0,0 +1,108 @@ +#ifdef APU_CPP + +bool APU::Noise::dac_enable() { + return (envelope_volume || envelope_direction); +} + +void APU::Noise::run() { + if(period && --period == 0) { + period = divisor << frequency; + if(frequency < 14) { + bool bit = (lfsr ^ (lfsr >> 1)) & 1; + lfsr = (lfsr >> 1) ^ (bit << (narrow_lfsr ? 6 : 14)); + } + } + + uint4 sample = (lfsr & 1) ? (uint4)0 : volume; + if(enable == false) sample = 0; + + output = sample; +} + +void APU::Noise::clock_length() { + if(counter && length) { + if(--length == 0) enable = false; + } +} + +void APU::Noise::clock_envelope() { + if(enable && envelope_frequency && --envelope_period == 0) { + envelope_period = envelope_frequency; + if(envelope_direction == 0 && volume > 0) volume--; + if(envelope_direction == 1 && volume < 15) volume++; + } +} + +void APU::Noise::write(unsigned r, uint8 data) { + if(r == 1) { //$ff20 NR41 + length = 64 - (data & 0x3f); + } + + if(r == 2) { //$ff21 NR42 + envelope_volume = data >> 4; + envelope_direction = data & 0x08; + envelope_frequency = data & 0x07; + if(dac_enable() == false) enable = false; + } + + if(r == 3) { //$ff22 NR43 + frequency = data >> 4; + narrow_lfsr = data & 0x08; + divisor = (data & 0x07) << 4; + if(divisor == 0) divisor = 8; + period = divisor << frequency; + } + + if(r == 4) { //$ff34 NR44 + bool initialize = data & 0x80; + counter = data & 0x40; + + if(initialize) { + enable = dac_enable(); + lfsr = ~0U; + envelope_period = envelope_frequency; + volume = envelope_volume; + if(length == 0) length = 64; + } + } +} + +void APU::Noise::power() { + enable = 0; + + envelope_volume = 0; + envelope_direction = 0; + envelope_frequency = 0; + frequency = 0; + narrow_lfsr = 0; + divisor = 0; + counter = 0; + + output = 0; + length = 0; + envelope_period = 0; + volume = 0; + period = 0; + lfsr = 0; +} + +void APU::Noise::serialize(serializer &s) { + s.integer(enable); + + s.integer(envelope_volume); + s.integer(envelope_direction); + s.integer(envelope_frequency); + s.integer(frequency); + s.integer(narrow_lfsr); + s.integer(divisor); + s.integer(counter); + + s.integer(output); + s.integer(length); + s.integer(envelope_period); + s.integer(volume); + s.integer(period); + s.integer(lfsr); +} + +#endif diff --git a/gameboy/apu/noise/noise.hpp b/gameboy/apu/noise/noise.hpp new file mode 100755 index 00000000..f92efbf3 --- /dev/null +++ b/gameboy/apu/noise/noise.hpp @@ -0,0 +1,27 @@ +struct Noise { + bool enable; + + uint4 envelope_volume; + bool envelope_direction; + uint3 envelope_frequency; + uint4 frequency; + bool narrow_lfsr; + unsigned divisor; + bool counter; + + int16 output; + unsigned length; + uint3 envelope_period; + uint4 volume; + unsigned period; + uint15 lfsr; + + bool dac_enable(); + + void run(); + void clock_length(); + void clock_envelope(); + void write(unsigned r, uint8 data); + void power(); + void serialize(serializer&); +}; diff --git a/gameboy/apu/serialization.cpp b/gameboy/apu/serialization.cpp new file mode 100755 index 00000000..34686347 --- /dev/null +++ b/gameboy/apu/serialization.cpp @@ -0,0 +1,17 @@ +#ifdef APU_CPP + +void APU::serialize(serializer &s) { + Processor::serialize(s); + + s.array(mmio_data); + s.integer(sequencer_base); + s.integer(sequencer_step); + + square1.serialize(s); + square2.serialize(s); + wave.serialize(s); + noise.serialize(s); + master.serialize(s); +} + +#endif diff --git a/gameboy/apu/square1/square1.cpp b/gameboy/apu/square1/square1.cpp new file mode 100755 index 00000000..0a9e0132 --- /dev/null +++ b/gameboy/apu/square1/square1.cpp @@ -0,0 +1,160 @@ +#ifdef APU_CPP + +bool APU::Square1::dac_enable() { + return (envelope_volume || envelope_direction); +} + +void APU::Square1::run() { + if(period && --period == 0) { + period = 4 * (2048 - frequency); + phase++; + switch(duty) { + case 0: duty_output = (phase == 6); break; //______-_ + case 1: duty_output = (phase >= 6); break; //______-- + case 2: duty_output = (phase >= 4); break; //____---- + case 3: duty_output = (phase <= 5); break; //------__ + } + } + + uint4 sample = (duty_output ? volume : (uint4)0); + if(enable == false) sample = 0; + + output = sample; +} + +void APU::Square1::sweep(bool update) { + if(sweep_enable == false) return; + + sweep_negate = sweep_direction; + unsigned delta = frequency_shadow >> sweep_shift; + signed freq = frequency_shadow + (sweep_negate ? -delta : delta); + + if(freq > 2047) { + enable = false; + } else if(sweep_shift && update) { + frequency_shadow = freq; + frequency = freq & 2047; + period = 4 * (2048 - frequency); + } +} + +void APU::Square1::clock_length() { + if(counter && length) { + if(--length == 0) enable = false; + } +} + +void APU::Square1::clock_sweep() { + if(enable && sweep_frequency && --sweep_period == 0) { + sweep_period = sweep_frequency; + sweep(1); + sweep(0); + } +} + +void APU::Square1::clock_envelope() { + if(enable && envelope_frequency && --envelope_period == 0) { + envelope_period = envelope_frequency; + if(envelope_direction == 0 && volume > 0) volume--; + if(envelope_direction == 1 && volume < 15) volume++; + } +} + +void APU::Square1::write(unsigned r, uint8 data) { + if(r == 0) { //$ff10 NR10 + if(sweep_negate && sweep_direction && !(data & 0x08)) enable = false; + sweep_frequency = (data >> 4) & 7; + sweep_direction = data & 0x08; + sweep_shift = data & 0x07; + } + + if(r == 1) { //$ff11 NR11 + duty = data >> 6; + length = 64 - (data & 0x3f); + } + + if(r == 2) { //$ff12 NR12 + envelope_volume = data >> 4; + envelope_direction = data & 0x08; + envelope_frequency = data & 0x07; + if(dac_enable() == false) enable = false; + } + + if(r == 3) { //$ff13 NR13 + frequency = (frequency & 0x0700) | data; + } + + if(r == 4) { //$ff14 NR14 + bool initialize = data & 0x80; + counter = data & 0x40; + frequency = ((data & 7) << 8) | (frequency & 0x00ff); + + if(initialize) { + enable = dac_enable(); + envelope_period = envelope_frequency; + volume = envelope_volume; + frequency_shadow = frequency; + sweep_period = sweep_frequency; + sweep_enable = sweep_period || sweep_shift; + sweep_negate = false; + if(sweep_shift) sweep(0); + if(length == 0) length = 64; + } + } + + period = 4 * (2048 - frequency); +} + +void APU::Square1::power() { + enable = 0; + + sweep_frequency = 0; + sweep_direction = 0; + sweep_shift = 0; + sweep_negate = 0; + duty = 0; + length = 0; + envelope_volume = 0; + envelope_direction = 0; + envelope_frequency = 0; + frequency = 0; + counter = 0; + + output = 0; + duty_output = 0; + phase = 0; + period = 0; + envelope_period = 0; + sweep_period = 0; + frequency_shadow = 0; + sweep_enable = 0; + volume = 0; +} + +void APU::Square1::serialize(serializer &s) { + s.integer(enable); + + s.integer(sweep_frequency); + s.integer(sweep_direction); + s.integer(sweep_shift); + s.integer(sweep_negate); + s.integer(duty); + s.integer(length); + s.integer(envelope_volume); + s.integer(envelope_direction); + s.integer(envelope_frequency); + s.integer(frequency); + s.integer(counter); + + s.integer(output); + s.integer(duty_output); + s.integer(phase); + s.integer(period); + s.integer(envelope_period); + s.integer(sweep_period); + s.integer(frequency_shadow); + s.integer(sweep_enable); + s.integer(volume); +} + +#endif diff --git a/gameboy/apu/square1/square1.hpp b/gameboy/apu/square1/square1.hpp new file mode 100755 index 00000000..2b45676f --- /dev/null +++ b/gameboy/apu/square1/square1.hpp @@ -0,0 +1,36 @@ +struct Square1 { + bool enable; + + uint3 sweep_frequency; + bool sweep_direction; + uint3 sweep_shift; + bool sweep_negate; + uint2 duty; + unsigned length; + uint4 envelope_volume; + bool envelope_direction; + uint3 envelope_frequency; + uint11 frequency; + bool counter; + + int16 output; + bool duty_output; + uint3 phase; + unsigned period; + uint3 envelope_period; + uint3 sweep_period; + signed frequency_shadow; + bool sweep_enable; + uint4 volume; + + bool dac_enable(); + + void run(); + void sweep(bool update); + void clock_length(); + void clock_sweep(); + void clock_envelope(); + void write(unsigned r, uint8 data); + void power(); + void serialize(serializer&); +}; diff --git a/gameboy/apu/square2/square2.cpp b/gameboy/apu/square2/square2.cpp new file mode 100755 index 00000000..09e50678 --- /dev/null +++ b/gameboy/apu/square2/square2.cpp @@ -0,0 +1,110 @@ +#ifdef APU_CPP + +bool APU::Square2::dac_enable() { + return (envelope_volume || envelope_direction); +} + +void APU::Square2::run() { + if(period && --period == 0) { + period = 4 * (2048 - frequency); + phase++; + switch(duty) { + case 0: duty_output = (phase == 6); break; //______-_ + case 1: duty_output = (phase >= 6); break; //______-- + case 2: duty_output = (phase >= 4); break; //____---- + case 3: duty_output = (phase <= 5); break; //------__ + } + } + + uint4 sample = (duty_output ? volume : (uint4)0); + if(enable == false) sample = 0; + + output = sample; +} + +void APU::Square2::clock_length() { + if(counter && length) { + if(--length == 0) enable = false; + } +} + +void APU::Square2::clock_envelope() { + if(enable && envelope_frequency && --envelope_period == 0) { + envelope_period = envelope_frequency; + if(envelope_direction == 0 && volume > 0) volume--; + if(envelope_direction == 1 && volume < 15) volume++; + } +} + +void APU::Square2::write(unsigned r, uint8 data) { + if(r == 1) { //$ff16 NR21 + duty = data >> 6; + length = 64 - (data & 0x3f); + } + + if(r == 2) { //$ff17 NR22 + envelope_volume = data >> 4; + envelope_direction = data & 0x08; + envelope_frequency = data & 0x07; + if(dac_enable() == false) enable = false; + } + + if(r == 3) { //$ff18 NR23 + frequency = (frequency & 0x0700) | data; + } + + if(r == 4) { //$ff19 NR24 + bool initialize = data & 0x80; + counter = data & 0x40; + frequency = ((data & 7) << 8) | (frequency & 0x00ff); + + if(initialize) { + enable = dac_enable(); + envelope_period = envelope_frequency; + volume = envelope_volume; + if(length == 0) length = 64; + } + } + + period = 4 * (2048 - frequency); +} + +void APU::Square2::power() { + enable = 0; + + duty = 0; + length = 0; + envelope_volume = 0; + envelope_direction = 0; + envelope_frequency = 0; + frequency = 0; + counter = 0; + + output = 0; + duty_output = 0; + phase = 0; + period = 0; + envelope_period = 0; + volume = 0; +} + +void APU::Square2::serialize(serializer &s) { + s.integer(enable); + + s.integer(duty); + s.integer(length); + s.integer(envelope_volume); + s.integer(envelope_direction); + s.integer(envelope_frequency); + s.integer(frequency); + s.integer(counter); + + s.integer(output); + s.integer(duty_output); + s.integer(phase); + s.integer(period); + s.integer(envelope_period); + s.integer(volume); +} + +#endif diff --git a/gameboy/apu/square2/square2.hpp b/gameboy/apu/square2/square2.hpp new file mode 100755 index 00000000..0a473348 --- /dev/null +++ b/gameboy/apu/square2/square2.hpp @@ -0,0 +1,27 @@ +struct Square2 { + bool enable; + + uint2 duty; + unsigned length; + uint4 envelope_volume; + bool envelope_direction; + uint3 envelope_frequency; + uint11 frequency; + bool counter; + + int16 output; + bool duty_output; + uint3 phase; + unsigned period; + uint3 envelope_period; + uint4 volume; + + bool dac_enable(); + + void run(); + void clock_length(); + void clock_envelope(); + void write(unsigned r, uint8 data); + void power(); + void serialize(serializer&); +}; diff --git a/gameboy/apu/wave/wave.cpp b/gameboy/apu/wave/wave.cpp new file mode 100755 index 00000000..498cd8f6 --- /dev/null +++ b/gameboy/apu/wave/wave.cpp @@ -0,0 +1,99 @@ +#ifdef APU_CPP + +void APU::Wave::run() { + if(period && --period == 0) { + period = 2 * (2048 - frequency); + pattern_sample = pattern[++pattern_offset]; + } + + uint4 sample = pattern_sample >> volume_shift; + if(enable == false) sample = 0; + + output = sample; +} + +void APU::Wave::clock_length() { + if(counter && length) { + if(--length == 0) enable = false; + } +} + +void APU::Wave::write(unsigned r, uint8 data) { + if(r == 0) { //$ff1a NR30 + dac_enable = data & 0x80; + if(dac_enable == false) enable = false; + } + + if(r == 1) { //$ff1b NR31 + length = 256 - data; + } + + if(r == 2) { //$ff1c NR32 + switch((data >> 5) & 3) { + case 0: volume_shift = 4; break; // 0% + case 1: volume_shift = 0; break; //100% + case 2: volume_shift = 1; break; // 50% + case 3: volume_shift = 2; break; // 25% + } + } + + if(r == 3) { //$ff1d NR33 + frequency = (frequency & 0x0700) | data; + } + + if(r == 4) { //$ff1e NR34 + bool initialize = data & 0x80; + counter = data & 0x40; + frequency = ((data & 7) << 8) | (frequency & 0x00ff); + + if(initialize) { + enable = dac_enable; + pattern_offset = 0; + if(length == 0) length = 256; + } + } + + period = 2 * (2048 - frequency); +} + +void APU::Wave::write_pattern(unsigned p, uint8 data) { + p <<= 1; + pattern[p + 0] = (data >> 4) & 15; + pattern[p + 1] = (data >> 0) & 15; +} + +void APU::Wave::power() { + enable = 0; + + dac_enable = 0; + volume_shift = 0; + frequency = 0; + counter = 0; + + random_lfsr r; + for(auto &n : pattern) n = r() & 15; + + output = 0; + length = 0; + period = 0; + pattern_offset = 0; + pattern_sample = 0; +} + +void APU::Wave::serialize(serializer &s) { + s.integer(enable); + + s.integer(dac_enable); + s.integer(volume_shift); + s.integer(frequency); + s.integer(counter); + s.array(pattern); + + s.integer(output); + s.integer(length); + s.integer(period); + s.integer(pattern_offset); + s.integer(pattern_sample); +} + +#endif diff --git a/gameboy/apu/wave/wave.hpp b/gameboy/apu/wave/wave.hpp new file mode 100755 index 00000000..7f8d65d3 --- /dev/null +++ b/gameboy/apu/wave/wave.hpp @@ -0,0 +1,22 @@ +struct Wave { + bool enable; + + bool dac_enable; + unsigned volume_shift; + uint11 frequency; + bool counter; + uint8 pattern[32]; + + int16 output; + unsigned length; + unsigned period; + uint5 pattern_offset; + uint4 pattern_sample; + + void run(); + void clock_length(); + void write(unsigned r, uint8 data); + void write_pattern(unsigned p, uint8 data); + void power(); + void serialize(serializer&); +}; diff --git a/gameboy/cartridge/cartridge.cpp b/gameboy/cartridge/cartridge.cpp new file mode 100755 index 00000000..566a8ad0 --- /dev/null +++ b/gameboy/cartridge/cartridge.cpp @@ -0,0 +1,153 @@ +#include + +#include + +#define CARTRIDGE_CPP +namespace GameBoy { + +#include "mbc0/mbc0.cpp" +#include "mbc1/mbc1.cpp" +#include "mbc2/mbc2.cpp" +#include "mbc3/mbc3.cpp" +#include "mbc5/mbc5.cpp" +#include "mmm01/mmm01.cpp" +#include "huc1/huc1.cpp" +#include "huc3/huc3.cpp" +#include "serialization.cpp" +Cartridge cartridge; + +void Cartridge::load(System::Revision revision, const string &markup, const uint8_t *data, unsigned size) { + if(size == 0) size = 32768; + romdata = allocate(romsize = size, 0xff); + if(data) memcpy(romdata, data, size); + + info.mapper = Mapper::Unknown; + info.ram = false; + info.battery = false; + info.rtc = false; + info.rumble = false; + + info.romsize = 0; + info.ramsize = 0; + + BML::Document document(markup); + + auto &mapperid = document["cartridge"]["mapper"].value; + if(mapperid == "none" ) info.mapper = Mapper::MBC0; + if(mapperid == "MBC1" ) info.mapper = Mapper::MBC1; + if(mapperid == "MBC2" ) info.mapper = Mapper::MBC2; + if(mapperid == "MBC3" ) info.mapper = Mapper::MBC3; + if(mapperid == "MBC5" ) info.mapper = Mapper::MBC5; + if(mapperid == "MMM01") info.mapper = Mapper::MMM01; + if(mapperid == "HuC1" ) info.mapper = Mapper::HuC1; + if(mapperid == "HuC3" ) info.mapper = Mapper::HuC3; + + info.rtc = document["cartridge"]["rtc"].exists(); + info.rumble = document["cartridge"]["rumble"].exists(); + + info.romsize = hex(document["cartridge"]["rom"]["size"].value); + info.ramsize = hex(document["cartridge"]["ram"]["size"].value); + info.battery = document["cartridge"]["ram"]["non-volatile"].exists(); + + switch(info.mapper) { default: + case Mapper::MBC0: mapper = &mbc0; break; + case Mapper::MBC1: mapper = &mbc1; break; + case Mapper::MBC2: mapper = &mbc2; break; + case Mapper::MBC3: mapper = &mbc3; break; + case Mapper::MBC5: mapper = &mbc5; break; + case Mapper::MMM01: mapper = &mmm01; break; + case Mapper::HuC1: mapper = &huc1; break; + case Mapper::HuC3: mapper = &huc3; break; + } + + ramdata = new uint8_t[ramsize = info.ramsize](); + system.load(revision); + + loaded = true; + sha256 = nall::sha256(romdata, romsize); +} + +void Cartridge::unload() { + if(loaded == false) return; + + if(romdata) { delete[] romdata; romdata = 0; } + if(ramdata) { delete[] ramdata; ramdata = 0; } + loaded = false; +} + +uint8 Cartridge::rom_read(unsigned addr) { + if(addr >= romsize) addr %= romsize; + return romdata[addr]; +} + +void Cartridge::rom_write(unsigned addr, uint8 data) { + if(addr >= romsize) addr %= romsize; + romdata[addr] = data; +} + +uint8 Cartridge::ram_read(unsigned addr) { + if(ramsize == 0) return 0x00; + if(addr >= ramsize) addr %= ramsize; + return ramdata[addr]; +} + +void Cartridge::ram_write(unsigned addr, uint8 data) { + if(ramsize == 0) return; + if(addr >= ramsize) addr %= ramsize; + ramdata[addr] = data; +} + +uint8 Cartridge::mmio_read(uint16 addr) { + if(addr == 0xff50) return 0x00; + + if(bootrom_enable) { + const uint8 *data = nullptr; + switch(system.revision()) { default: + case System::Revision::GameBoy: data = System::BootROM::dmg; break; + case System::Revision::SuperGameBoy: data = System::BootROM::sgb; break; + case System::Revision::GameBoyColor: data = System::BootROM::cgb; break; + } + if(addr >= 0x0000 && addr <= 0x00ff) return data[addr]; + if(addr >= 0x0200 && addr <= 0x08ff && system.cgb()) return data[addr - 256]; + } + + return mapper->mmio_read(addr); +} + +void Cartridge::mmio_write(uint16 addr, uint8 data) { + if(bootrom_enable && addr == 0xff50) { + bootrom_enable = false; + return; + } + + mapper->mmio_write(addr, data); +} + +void Cartridge::power() { + bootrom_enable = true; + + mbc0.power(); + mbc1.power(); + mbc2.power(); + mbc3.power(); + mbc5.power(); + mmm01.power(); + huc1.power(); + huc3.power(); + + for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this; + for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this; + bus.mmio[0xff50] = this; +} + +Cartridge::Cartridge() { + loaded = false; + romdata = 0; + ramdata = 0; +} + +Cartridge::~Cartridge() { + unload(); +} + +} diff --git a/gameboy/cartridge/cartridge.hpp b/gameboy/cartridge/cartridge.hpp new file mode 100755 index 00000000..d7e4c2a5 --- /dev/null +++ b/gameboy/cartridge/cartridge.hpp @@ -0,0 +1,66 @@ +struct Cartridge : MMIO, property { + #include "mbc0/mbc0.hpp" + #include "mbc1/mbc1.hpp" + #include "mbc2/mbc2.hpp" + #include "mbc3/mbc3.hpp" + #include "mbc5/mbc5.hpp" + #include "mmm01/mmm01.hpp" + #include "huc1/huc1.hpp" + #include "huc3/huc3.hpp" + + enum Mapper : unsigned { + MBC0, + MBC1, + MBC2, + MBC3, + MBC5, + MMM01, + HuC1, + HuC3, + Unknown, + }; + + struct Information { + string xml; + + Mapper mapper; + bool ram; + bool battery; + bool rtc; + bool rumble; + + unsigned romsize; + unsigned ramsize; + } info; + + readonly loaded; + readonly sha256; + + uint8_t *romdata; + unsigned romsize; + + uint8_t *ramdata; + unsigned ramsize; + + MMIO *mapper; + bool bootrom_enable; + + void load(System::Revision revision, const string &markup, const uint8_t *data, unsigned size); + void unload(); + + uint8 rom_read(unsigned addr); + void rom_write(unsigned addr, uint8 data); + uint8 ram_read(unsigned addr); + void ram_write(unsigned addr, uint8 data); + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + + void power(); + + void serialize(serializer&); + Cartridge(); + ~Cartridge(); +}; + +extern Cartridge cartridge; diff --git a/gameboy/cartridge/huc1/huc1.cpp b/gameboy/cartridge/huc1/huc1.cpp new file mode 100755 index 00000000..8a5531eb --- /dev/null +++ b/gameboy/cartridge/huc1/huc1.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::HuC1::mmio_read(uint16 addr) { + if(within<0x0000, 0x3fff>(addr)) { + return cartridge.rom_read(addr); + } + + if(within<0x4000, 0x7fff>(addr)) { + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) { + if(within<0x0000, 0x1fff>(addr)) { + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if(within<0x2000, 0x3fff>(addr)) { + rom_select = data; + return; + } + + if(within<0x4000, 0x5fff>(addr)) { + ram_select = data; + return; + } + + if(within<0x6000, 0x7fff>(addr)) { + //unknown purpose + return; + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; + } +} + +void Cartridge::HuC1::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/gameboy/cartridge/huc1/huc1.hpp b/gameboy/cartridge/huc1/huc1.hpp new file mode 100755 index 00000000..f7bcc37d --- /dev/null +++ b/gameboy/cartridge/huc1/huc1.hpp @@ -0,0 +1,9 @@ +struct HuC1 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} huc1; diff --git a/gameboy/cartridge/huc3/huc3.cpp b/gameboy/cartridge/huc3/huc3.cpp new file mode 100755 index 00000000..efaa9af0 --- /dev/null +++ b/gameboy/cartridge/huc3/huc3.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::HuC3::mmio_read(uint16 addr) { + if(within<0x0000, 0x3fff>(addr)) { + return cartridge.rom_read(addr); + } + + if(within<0x4000, 0x7fff>(addr)) { + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) { + if(within<0x0000, 0x1fff>(addr)) { + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if(within<0x2000, 0x3fff>(addr)) { + rom_select = data; + return; + } + + if(within<0x4000, 0x5fff>(addr)) { + ram_select = data; + return; + } + + if(within<0x6000, 0x7fff>(addr)) { + //unknown purpose + return; + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; + } +} + +void Cartridge::HuC3::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/gameboy/cartridge/huc3/huc3.hpp b/gameboy/cartridge/huc3/huc3.hpp new file mode 100755 index 00000000..407d3bd4 --- /dev/null +++ b/gameboy/cartridge/huc3/huc3.hpp @@ -0,0 +1,9 @@ +struct HuC3 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} huc3; diff --git a/gameboy/cartridge/mbc0/mbc0.cpp b/gameboy/cartridge/mbc0/mbc0.cpp new file mode 100755 index 00000000..f3280f31 --- /dev/null +++ b/gameboy/cartridge/mbc0/mbc0.cpp @@ -0,0 +1,25 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MBC0::mmio_read(uint16 addr) { + if(within<0x0000, 0x7fff>(addr)) { + return cartridge.rom_read(addr); + } + + if(within<0xa000, 0xbfff>(addr)) { + return cartridge.ram_read(addr & 0x1fff); + } + + return 0x00; +} + +void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) { + if(within<0xa000, 0xbfff>(addr)) { + cartridge.ram_write(addr & 0x1fff, data); + return; + } +} + +void Cartridge::MBC0::power() { +} + +#endif diff --git a/gameboy/cartridge/mbc0/mbc0.hpp b/gameboy/cartridge/mbc0/mbc0.hpp new file mode 100755 index 00000000..da7390ea --- /dev/null +++ b/gameboy/cartridge/mbc0/mbc0.hpp @@ -0,0 +1,5 @@ +struct MBC0 : MMIO { + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc0; diff --git a/gameboy/cartridge/mbc1/mbc1.cpp b/gameboy/cartridge/mbc1/mbc1.cpp new file mode 100755 index 00000000..d254e7fe --- /dev/null +++ b/gameboy/cartridge/mbc1/mbc1.cpp @@ -0,0 +1,70 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MBC1::mmio_read(uint16 addr) { + if(within<0x0000, 0x3fff>(addr)) { + return cartridge.rom_read(addr); + } + + if(within<0x4000, 0x7fff>(addr)) { + if(mode_select == 0) { + return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff)); + } else { + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) { + if(mode_select == 0) { + return cartridge.ram_read(addr & 0x1fff); + } else { + return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + } + } + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) { + if(within<0x0000, 0x1fff>(addr)) { + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if(within<0x2000, 0x3fff>(addr)) { + rom_select = (data & 0x1f) + ((data & 0x1f) == 0); + return; + } + + if(within<0x4000, 0x5fff>(addr)) { + ram_select = data & 0x03; + return; + } + + if(within<0x6000, 0x7fff>(addr)) { + mode_select = data & 0x01; + return; + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) { + if(mode_select == 0) { + cartridge.ram_write(addr & 0x1fff, data); + } else { + cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + } + } + return; + } +} + +void Cartridge::MBC1::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; + mode_select = 0; +} + +#endif diff --git a/gameboy/cartridge/mbc1/mbc1.hpp b/gameboy/cartridge/mbc1/mbc1.hpp new file mode 100755 index 00000000..099cf43d --- /dev/null +++ b/gameboy/cartridge/mbc1/mbc1.hpp @@ -0,0 +1,10 @@ +struct MBC1 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + bool mode_select; //6000-7fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc1; diff --git a/gameboy/cartridge/mbc2/mbc2.cpp b/gameboy/cartridge/mbc2/mbc2.cpp new file mode 100755 index 00000000..d5c9be1a --- /dev/null +++ b/gameboy/cartridge/mbc2/mbc2.cpp @@ -0,0 +1,42 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MBC2::mmio_read(uint16 addr) { + if(within<0x0000, 0x3fff>(addr)) { + return cartridge.rom_read(addr); + } + + if(within<0x4000, 0x7fff>(addr)) { + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if(within<0xa000, 0xa1ff>(addr)) { + if(ram_enable) return cartridge.ram_read(addr & 0x1ff); + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) { + if(within<0x0000, 0x1fff>(addr)) { + if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if(within<0x2000, 0x3fff>(addr)) { + if( (addr & 0x0100)) rom_select = (data & 0x0f) + ((data & 0x0f) == 0); + return; + } + + if(within<0xa000, 0xa1ff>(addr)) { + if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f); + return; + } +} + +void Cartridge::MBC2::power() { + ram_enable = false; + rom_select = 0x01; +} + +#endif diff --git a/gameboy/cartridge/mbc2/mbc2.hpp b/gameboy/cartridge/mbc2/mbc2.hpp new file mode 100755 index 00000000..be9b7db6 --- /dev/null +++ b/gameboy/cartridge/mbc2/mbc2.hpp @@ -0,0 +1,8 @@ +struct MBC2 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc2; diff --git a/gameboy/cartridge/mbc3/mbc3.cpp b/gameboy/cartridge/mbc3/mbc3.cpp new file mode 100755 index 00000000..d04ca8c0 --- /dev/null +++ b/gameboy/cartridge/mbc3/mbc3.cpp @@ -0,0 +1,120 @@ +#ifdef CARTRIDGE_CPP + +void Cartridge::MBC3::second() { + if(rtc_halt == false) { + if(++rtc_second >= 60) { + rtc_second = 0; + if(++rtc_minute >= 60) { + rtc_minute = 0; + if(++rtc_hour >= 24) { + rtc_hour = 0; + if(++rtc_day >= 512) { + rtc_day = 0; + rtc_day_carry = true; + } + } + } + } + } +} + +uint8 Cartridge::MBC3::mmio_read(uint16 addr) { + if(within<0x0000, 0x3fff>(addr)) { + return cartridge.rom_read(addr); + } + + if(within<0x4000, 0x7fff>(addr)) { + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) { + if(ram_select >= 0x00 && ram_select <= 0x03) { + return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + } + if(ram_select == 0x08) return rtc_latch_second; + if(ram_select == 0x09) return rtc_latch_minute; + if(ram_select == 0x0a) return rtc_latch_hour; + if(ram_select == 0x0b) return rtc_latch_day; + if(ram_select == 0x0c) return (rtc_latch_day_carry << 7) | (rtc_latch_day >> 8); + } + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) { + if(within<0x0000, 0x1fff>(addr)) { + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if(within<0x2000, 0x3fff>(addr)) { + rom_select = (data & 0x7f) + ((data & 0x7f) == 0); + return; + } + + if(within<0x4000, 0x5fff>(addr)) { + ram_select = data; + return; + } + + if(within<0x6000, 0x7fff>(addr)) { + if(rtc_latch == 0 && data == 1) { + rtc_latch_second = rtc_second; + rtc_latch_minute = rtc_minute; + rtc_latch_hour = rtc_hour; + rtc_latch_day = rtc_day; + rtc_latch_day_carry = rtc_day_carry; + } + rtc_latch = data; + return; + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) { + if(ram_select >= 0x00 && ram_select <= 0x03) { + cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + } else if(ram_select == 0x08) { + if(data >= 60) data = 0; + rtc_second = data; + } else if(ram_select == 0x09) { + if(data >= 60) data = 0; + rtc_minute = data; + } else if(ram_select == 0x0a) { + if(data >= 24) data = 0; + rtc_hour = data; + } else if(ram_select == 0x0b) { + rtc_day = (rtc_day & 0x0100) | data; + } else if(ram_select == 0x0c) { + rtc_day = ((data & 1) << 8) | (rtc_day & 0xff); + rtc_halt = data & 0x40; + rtc_day_carry = data & 0x80; + } + } + return; + } +} + +void Cartridge::MBC3::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; + rtc_latch = 0; + + rtc_halt = true; + rtc_second = 0; + rtc_minute = 0; + rtc_hour = 0; + rtc_day = 0; + rtc_day_carry = false; + + rtc_latch_second = 0; + rtc_latch_minute = 0; + rtc_latch_hour = 0; + rtc_latch_day = 0; + rtc_latch_day_carry = false; +} + +#endif diff --git a/gameboy/cartridge/mbc3/mbc3.hpp b/gameboy/cartridge/mbc3/mbc3.hpp new file mode 100755 index 00000000..d83ba182 --- /dev/null +++ b/gameboy/cartridge/mbc3/mbc3.hpp @@ -0,0 +1,24 @@ +struct MBC3 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + bool rtc_latch; //6000-7fff + + bool rtc_halt; + unsigned rtc_second; + unsigned rtc_minute; + unsigned rtc_hour; + unsigned rtc_day; + bool rtc_day_carry; + + unsigned rtc_latch_second; + unsigned rtc_latch_minute; + unsigned rtc_latch_hour; + unsigned rtc_latch_day; + unsigned rtc_latch_day_carry; + + void second(); + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc3; diff --git a/gameboy/cartridge/mbc5/mbc5.cpp b/gameboy/cartridge/mbc5/mbc5.cpp new file mode 100755 index 00000000..4dc215bb --- /dev/null +++ b/gameboy/cartridge/mbc5/mbc5.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MBC5::mmio_read(uint16 addr) { + if(within<0x0000, 0x3fff>(addr)) { + return cartridge.rom_read(addr); + } + + if(within<0x4000, 0x7fff>(addr)) { + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) { + if(within<0x0000, 0x1fff>(addr)) { + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if(within<0x2000, 0x2fff>(addr)) { + rom_select = (rom_select & 0x0100) | data; + return; + } + + if(within<0x3000, 0x3fff>(addr)) { + rom_select = ((data & 1) << 8) | (rom_select & 0x00ff); + return; + } + + if(within<0x4000, 0x5fff>(addr)) { + ram_select = data & 0x0f; + return; + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; + } +} + +void Cartridge::MBC5::power() { + ram_enable = false; + rom_select = 0x001; + ram_select = 0x00; +} + +#endif diff --git a/gameboy/cartridge/mbc5/mbc5.hpp b/gameboy/cartridge/mbc5/mbc5.hpp new file mode 100755 index 00000000..7d5b0a30 --- /dev/null +++ b/gameboy/cartridge/mbc5/mbc5.hpp @@ -0,0 +1,9 @@ +struct MBC5 : MMIO { + bool ram_enable; //0000-1fff + uint16 rom_select; //2000-2fff + 3000-3fff + uint8 ram_select; //4000-5fff + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc5; diff --git a/gameboy/cartridge/mmm01/mmm01.cpp b/gameboy/cartridge/mmm01/mmm01.cpp new file mode 100755 index 00000000..4ad9fae0 --- /dev/null +++ b/gameboy/cartridge/mmm01/mmm01.cpp @@ -0,0 +1,65 @@ +#ifdef CARTRIDGE_CPP + +uint8 Cartridge::MMM01::mmio_read(uint16 addr) { + if(within<0x0000, 0x7fff>(addr)) { + if(rom_mode == 0) return cartridge.rom_read(addr); + } + + if(within<0x0000, 0x3fff>(addr)) { + return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff)); + } + + if(within<0x4000, 0x7fff>(addr)) { + return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff)); + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff)); + return 0x00; + } + + return 0x00; +} + +void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) { + if(within<0x0000, 0x1fff>(addr)) { + if(rom_mode == 0) { + rom_mode = 1; + } else { + ram_enable = (data & 0x0f) == 0x0a; + } + } + + if(within<0x2000, 0x3fff>(addr)) { + if(rom_mode == 0) { + rom_base = data & 0x3f; + } else { + rom_select = data; + } + } + + if(within<0x4000, 0x5fff>(addr)) { + if(rom_mode == 1) { + ram_select = data; + } + } + + if(within<0x6000, 0x7fff>(addr)) { + //unknown purpose + } + + if(within<0xa000, 0xbfff>(addr)) { + if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data); + } +} + +void Cartridge::MMM01::power() { + rom_mode = 0; + rom_base = 0; + + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; +} + +#endif diff --git a/gameboy/cartridge/mmm01/mmm01.hpp b/gameboy/cartridge/mmm01/mmm01.hpp new file mode 100755 index 00000000..3474b062 --- /dev/null +++ b/gameboy/cartridge/mmm01/mmm01.hpp @@ -0,0 +1,12 @@ +struct MMM01 : MMIO { + bool rom_mode; + uint8 rom_base; + + bool ram_enable; + uint8 rom_select; + uint8 ram_select; + + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mmm01; diff --git a/gameboy/cartridge/serialization.cpp b/gameboy/cartridge/serialization.cpp new file mode 100755 index 00000000..600d4d02 --- /dev/null +++ b/gameboy/cartridge/serialization.cpp @@ -0,0 +1,53 @@ +#ifdef CARTRIDGE_CPP + +void Cartridge::serialize(serializer &s) { + if(info.battery) s.array(ramdata, ramsize); + s.integer(bootrom_enable); + + s.integer(mbc1.ram_enable); + s.integer(mbc1.rom_select); + s.integer(mbc1.ram_select); + s.integer(mbc1.mode_select); + + s.integer(mbc2.ram_enable); + s.integer(mbc2.rom_select); + + s.integer(mbc3.ram_enable); + s.integer(mbc3.rom_select); + s.integer(mbc3.ram_select); + s.integer(mbc3.rtc_latch); + + s.integer(mbc3.rtc_halt); + s.integer(mbc3.rtc_second); + s.integer(mbc3.rtc_minute); + s.integer(mbc3.rtc_hour); + s.integer(mbc3.rtc_day); + s.integer(mbc3.rtc_day_carry); + + s.integer(mbc3.rtc_latch_second); + s.integer(mbc3.rtc_latch_minute); + s.integer(mbc3.rtc_latch_hour); + s.integer(mbc3.rtc_latch_day); + s.integer(mbc3.rtc_latch_day_carry); + + s.integer(mbc5.ram_enable); + s.integer(mbc5.rom_select); + s.integer(mbc5.ram_select); + + s.integer(mmm01.rom_mode); + s.integer(mmm01.rom_base); + + s.integer(mmm01.ram_enable); + s.integer(mmm01.rom_select); + s.integer(mmm01.ram_select); + + s.integer(huc1.ram_enable); + s.integer(huc1.rom_select); + s.integer(huc1.ram_select); + + s.integer(huc3.ram_enable); + s.integer(huc3.rom_select); + s.integer(huc3.ram_select); +} + +#endif diff --git a/gameboy/cheat/cheat.cpp b/gameboy/cheat/cheat.cpp new file mode 100755 index 00000000..bd72ef69 --- /dev/null +++ b/gameboy/cheat/cheat.cpp @@ -0,0 +1,91 @@ +#include + +namespace GameBoy { + +Cheat cheat; + +bool Cheat::decode(const string &code_, unsigned &addr, unsigned &data, unsigned &comp) { + static bool initialize = false; + static uint8 mapProActionReplay[256], mapGameGenie[256]; + + if(initialize == false) { + initialize = true; + + for(auto &n : mapProActionReplay) n = ~0; + mapProActionReplay['0'] = 0; mapProActionReplay['1'] = 1; mapProActionReplay['2'] = 2; mapProActionReplay['3'] = 3; + mapProActionReplay['4'] = 4; mapProActionReplay['5'] = 5; mapProActionReplay['6'] = 6; mapProActionReplay['7'] = 7; + mapProActionReplay['8'] = 8; mapProActionReplay['9'] = 9; mapProActionReplay['A'] = 10; mapProActionReplay['B'] = 11; + mapProActionReplay['C'] = 12; mapProActionReplay['D'] = 13; mapProActionReplay['E'] = 14; mapProActionReplay['F'] = 15; + + for(auto &n : mapGameGenie) n = ~0; + mapGameGenie['0'] = 0; mapGameGenie['1'] = 1; mapGameGenie['2'] = 2; mapGameGenie['3'] = 3; + mapGameGenie['4'] = 4; mapGameGenie['5'] = 5; mapGameGenie['6'] = 6; mapGameGenie['7'] = 7; + mapGameGenie['8'] = 8; mapGameGenie['9'] = 9; mapGameGenie['A'] = 10; mapGameGenie['B'] = 11; + mapGameGenie['C'] = 12; mapGameGenie['D'] = 13; mapGameGenie['E'] = 14; mapGameGenie['F'] = 15; + } + + string code = code_; + code.upper(); + unsigned length = code.length(), bits = 0; + + if(code.wildcard("????:??")) { + code = { substr(code, 0, 4), substr(code, 5, 2) }; + for(unsigned n = 0; n < 6; n++) if(mapProActionReplay[code[n]] > 15) return false; + bits = hex(code); + addr = (bits >> 8) & 0xffff; + data = (bits >> 0) & 0xff; + comp = ~0; + return true; + } + + if(code.wildcard("????:??:??")) { + code = { substr(code, 0, 4), substr(code, 5, 2), substr(code, 8, 2) }; + for(unsigned n = 0; n < 8; n++) if(mapProActionReplay[code[n]] > 15) return false; + bits = hex(code); + addr = (bits >> 16) & 0xffff; + data = (bits >> 8) & 0xff; + comp = (bits >> 0) & 0xff; + return true; + } + + if(code.wildcard("???" "-" "???")) { + code = { substr(code, 0, 3), substr(code, 4, 3) }; + for(unsigned n = 0; n < 6; n++) if(mapGameGenie[code[n]] > 15) return false; + for(unsigned n = 0; n < 6; n++) bits |= mapGameGenie[code[n]] << (20 - n * 4); + + addr = (bits >> 0) & 0xffff; + data = (bits >> 16) & 0xff; + comp = ~0; + + addr = (((addr >> 4) | (addr << 12)) & 0xffff) ^ 0xf000; + + return true; + } + + if(code.wildcard("???" "-" "???" "-" "???")) { + code = { substr(code, 0, 3), substr(code, 4, 3), substr(code, 8, 1), substr(code, 10, 1) }; + for(unsigned n = 0; n < 8; n++) if(mapGameGenie[code[n]] > 15) return false; + for(unsigned n = 0; n < 8; n++) bits |= mapGameGenie[code[n]] << (28 - n * 4); + + addr = (bits >> 8) & 0xffff; + data = (bits >> 24) & 0xff; + comp = (bits >> 0) & 0xff; + + addr = (((addr >> 4) | (addr << 12)) & 0xffff) ^ 0xf000; + comp = (((comp >> 2) | (comp << 6)) & 0xff) ^ 0xba; + + return true; + } + + return false; +} + +void Cheat::synchronize() { + for(auto &n : override) n = false; + + for(unsigned n = 0; n < size(); n++) { + override[operator[](n).addr] = true; + } +} + +} diff --git a/gameboy/cheat/cheat.hpp b/gameboy/cheat/cheat.hpp new file mode 100755 index 00000000..4446a52b --- /dev/null +++ b/gameboy/cheat/cheat.hpp @@ -0,0 +1,14 @@ +struct CheatCode { + unsigned addr; + unsigned data; + unsigned comp; +}; + +struct Cheat : public linear_vector { + static bool decode(const string &code, unsigned &addr, unsigned &data, unsigned &comp); + + void synchronize(); + bool override[65536]; +}; + +extern Cheat cheat; diff --git a/gameboy/cpu/core/core.cpp b/gameboy/cpu/core/core.cpp new file mode 100755 index 00000000..2f3601ac --- /dev/null +++ b/gameboy/cpu/core/core.cpp @@ -0,0 +1,682 @@ +#ifdef CPU_CPP + +#include "table.cpp" +#include "disassembler.cpp" + +void CPU::op_xx() { +} + +void CPU::op_cb() { + uint8 opcode = op_read(r[PC]++); + (this->*opcode_table_cb[opcode])(); +} + +//8-bit load commands + +template void CPU::op_ld_r_r() { + r[x] = r[y]; +} + +template void CPU::op_ld_r_n() { + r[x] = op_read(r[PC]++); +} + +template void CPU::op_ld_r_hl() { + r[x] = op_read(r[HL]); +} + +template void CPU::op_ld_hl_r() { + op_write(r[HL], r[x]); +} + +void CPU::op_ld_hl_n() { + op_write(r[HL], op_read(r[PC]++)); +} + +template void CPU::op_ld_a_rr() { + r[A] = op_read(r[x]); +} + +void CPU::op_ld_a_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + r[A] = op_read((hi << 8) | (lo << 0)); +} + +template void CPU::op_ld_rr_a() { + op_write(r[x], r[A]); +} + +void CPU::op_ld_nn_a() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + op_write((hi << 8) | (lo << 0), r[A]); +} + +void CPU::op_ld_a_ffn() { + r[A] = op_read(0xff00 + op_read(r[PC]++)); +} + +void CPU::op_ld_ffn_a() { + op_write(0xff00 + op_read(r[PC]++), r[A]); +} + +void CPU::op_ld_a_ffc() { + r[A] = op_read(0xff00 + r[C]); +} + +void CPU::op_ld_ffc_a() { + op_write(0xff00 + r[C], r[A]); +} + +void CPU::op_ldi_hl_a() { + op_write(r[HL], r[A]); + r[HL]++; +} + +void CPU::op_ldi_a_hl() { + r[A] = op_read(r[HL]); + r[HL]++; +} + +void CPU::op_ldd_hl_a() { + op_write(r[HL], r[A]); + r[HL]--; +} + +void CPU::op_ldd_a_hl() { + r[A] = op_read(r[HL]); + r[HL]--; +} + +//16-bit load commands + +template void CPU::op_ld_rr_nn() { + r[x] = op_read(r[PC]++) << 0; + r[x] |= op_read(r[PC]++) << 8; +} + +void CPU::op_ld_nn_sp() { + uint16 addr = op_read(r[PC]++) << 0; + addr |= op_read(r[PC]++) << 8; + op_write(addr + 0, r[SP] >> 0); + op_write(addr + 1, r[SP] >> 8); +} + +void CPU::op_ld_sp_hl() { + r[SP] = r[HL]; + op_io(); +} + +template void CPU::op_push_rr() { + op_write(--r[SP], r[x] >> 8); + op_write(--r[SP], r[x] >> 0); + op_io(); +} + +template void CPU::op_pop_rr() { + r[x] = op_read(r[SP]++) << 0; + r[x] |= op_read(r[SP]++) << 8; +} + +//8-bit arithmetic commands + +void CPU::opi_add_a(uint8 x) { + uint16 rh = r[A] + x; + uint16 rl = (r[A] & 0x0f) + (x & 0x0f); + r[A] = rh; + r.f.z = (uint8)rh == 0; + r.f.n = 0; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_add_a_r() { opi_add_a(r[x]); } +void CPU::op_add_a_n() { opi_add_a(op_read(r[PC]++)); } +void CPU::op_add_a_hl() { opi_add_a(op_read(r[HL])); } + +void CPU::opi_adc_a(uint8 x) { + uint16 rh = r[A] + x + r.f.c; + uint16 rl = (r[A] & 0x0f) + (x & 0x0f) + r.f.c; + r[A] = rh; + r.f.z = (uint8)rh == 0; + r.f.n = 0; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_adc_a_r() { opi_adc_a(r[x]); } +void CPU::op_adc_a_n() { opi_adc_a(op_read(r[PC]++)); } +void CPU::op_adc_a_hl() { opi_adc_a(op_read(r[HL])); } + +void CPU::opi_sub_a(uint8 x) { + uint16 rh = r[A] - x; + uint16 rl = (r[A] & 0x0f) - (x & 0x0f); + r[A] = rh; + r.f.z = (uint8)rh == 0; + r.f.n = 1; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_sub_a_r() { opi_sub_a(r[x]); } +void CPU::op_sub_a_n() { opi_sub_a(op_read(r[PC]++)); } +void CPU::op_sub_a_hl() { opi_sub_a(op_read(r[HL])); } + +void CPU::opi_sbc_a(uint8 x) { + uint16 rh = r[A] - x - r.f.c; + uint16 rl = (r[A] & 0x0f) - (x & 0x0f) - r.f.c; + r[A] = rh; + r.f.z = (uint8)rh == 0; + r.f.n = 1; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_sbc_a_r() { opi_sbc_a(r[x]); } +void CPU::op_sbc_a_n() { opi_sbc_a(op_read(r[PC]++)); } +void CPU::op_sbc_a_hl() { opi_sbc_a(op_read(r[HL])); } + +void CPU::opi_and_a(uint8 x) { + r[A] &= x; + r.f.z = r[A] == 0; + r.f.n = 0; + r.f.h = 1; + r.f.c = 0; +} + +template void CPU::op_and_a_r() { opi_and_a(r[x]); } +void CPU::op_and_a_n() { opi_and_a(op_read(r[PC]++)); } +void CPU::op_and_a_hl() { opi_and_a(op_read(r[HL])); } + +void CPU::opi_xor_a(uint8 x) { + r[A] ^= x; + r.f.z = r[A] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = 0; +} + +template void CPU::op_xor_a_r() { opi_xor_a(r[x]); } +void CPU::op_xor_a_n() { opi_xor_a(op_read(r[PC]++)); } +void CPU::op_xor_a_hl() { opi_xor_a(op_read(r[HL])); } + +void CPU::opi_or_a(uint8 x) { + r[A] |= x; + r.f.z = r[A] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = 0; +} + +template void CPU::op_or_a_r() { opi_or_a(r[x]); } +void CPU::op_or_a_n() { opi_or_a(op_read(r[PC]++)); } +void CPU::op_or_a_hl() { opi_or_a(op_read(r[HL])); } + +void CPU::opi_cp_a(uint8 x) { + uint16 rh = r[A] - x; + uint16 rl = (r[A] & 0x0f) - (x & 0x0f); + r.f.z = (uint8)rh == 0; + r.f.n = 1; + r.f.h = rl > 0x0f; + r.f.c = rh > 0xff; +} + +template void CPU::op_cp_a_r() { opi_cp_a(r[x]); } +void CPU::op_cp_a_n() { opi_cp_a(op_read(r[PC]++)); } +void CPU::op_cp_a_hl() { opi_cp_a(op_read(r[HL])); } + +template void CPU::op_inc_r() { + r[x]++; + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = (r[x] & 0x0f) == 0x00; +} + +void CPU::op_inc_hl() { + uint8 n = op_read(r[HL]); + op_write(r[HL], ++n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = (n & 0x0f) == 0x00; +} + +template void CPU::op_dec_r() { + r[x]--; + r.f.z = r[x] == 0; + r.f.n = 1; + r.f.h = (r[x] & 0x0f) == 0x0f; +} + +void CPU::op_dec_hl() { + uint8 n = op_read(r[HL]); + op_write(r[HL], --n); + r.f.z = n == 0; + r.f.n = 1; + r.f.h = (n & 0x0f) == 0x0f; +} + +void CPU::op_daa() { + uint16 a = r[A]; + if(r.f.n == 0) { + if(r.f.h || (a & 0x0f) > 0x09) a += 0x06; + if(r.f.c || (a ) > 0x9f) a += 0x60; + } else { + if(r.f.h) { + a -= 0x06; + if(r.f.c == 0) a &= 0xff; + } + if(r.f.c) a -= 0x60; + } + r[A] = a; + r.f.z = r[A] == 0; + r.f.h = 0; + r.f.c |= a & 0x100; +} + +void CPU::op_cpl() { + r[A] ^= 0xff; + r.f.n = 1; + r.f.h = 1; +} + +//16-bit arithmetic commands + +template void CPU::op_add_hl_rr() { + op_io(); + uint32 rb = (r[HL] + r[x]); + uint32 rn = (r[HL] & 0xfff) + (r[x] & 0xfff); + r[HL] = rb; + r.f.n = 0; + r.f.h = rn > 0x0fff; + r.f.c = rb > 0xffff; +} + +template void CPU::op_inc_rr() { + op_io(); + r[x]++; +} + +template void CPU::op_dec_rr() { + op_io(); + r[x]--; +} + +void CPU::op_add_sp_n() { + op_io(); + op_io(); + signed n = (int8)op_read(r[PC]++); + r.f.z = 0; + r.f.n = 0; + r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f; + r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff; + r[SP] += n; +} + +void CPU::op_ld_hl_sp_n() { + op_io(); + signed n = (int8)op_read(r[PC]++); + r.f.z = 0; + r.f.n = 0; + r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f; + r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff; + r[HL] = r[SP] + n; +} + +//rotate/shift commands + +void CPU::op_rlca() { + r[A] = (r[A] << 1) | (r[A] >> 7); + r.f.z = 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = r[A] & 0x01; +} + +void CPU::op_rla() { + bool c = r[A] & 0x80; + r[A] = (r[A] << 1) | (r.f.c << 0); + r.f.z = 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_rrca() { + r[A] = (r[A] >> 1) | (r[A] << 7); + r.f.z = 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = r[A] & 0x80; +} + +void CPU::op_rra() { + bool c = r[A] & 0x01; + r[A] = (r[A] >> 1) | (r.f.c << 7); + r.f.z = 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_rlc_r() { + r[x] = (r[x] << 1) | (r[x] >> 7); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = r[x] & 0x01; +} + +void CPU::op_rlc_hl() { + uint8 n = op_read(r[HL]); + n = (n << 1) | (n >> 7); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = n & 0x01; +} + +template void CPU::op_rl_r() { + bool c = r[x] & 0x80; + r[x] = (r[x] << 1) | (r.f.c << 0); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_rl_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x80; + n = (n << 1) | (r.f.c << 0); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_rrc_r() { + r[x] = (r[x] >> 1) | (r[x] << 7); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = r[x] & 0x80; +} + +void CPU::op_rrc_hl() { + uint8 n = op_read(r[HL]); + n = (n >> 1) | (n << 7); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = n & 0x80; +} + +template void CPU::op_rr_r() { + bool c = r[x] & 0x01; + r[x] = (r[x] >> 1) | (r.f.c << 7); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_rr_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x01; + n = (n >> 1) | (r.f.c << 7); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_sla_r() { + bool c = r[x] & 0x80; + r[x] <<= 1; + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_sla_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x80; + n <<= 1; + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_swap_r() { + r[x] = (r[x] << 4) | (r[x] >> 4); + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = 0; +} + +void CPU::op_swap_hl() { + uint8 n = op_read(r[HL]); + n = (n << 4) | (n >> 4); + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = 0; +} + +template void CPU::op_sra_r() { + bool c = r[x] & 0x01; + r[x] = (int8)r[x] >> 1; + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_sra_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x01; + n = (int8)n >> 1; + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +template void CPU::op_srl_r() { + bool c = r[x] & 0x01; + r[x] >>= 1; + r.f.z = r[x] == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +void CPU::op_srl_hl() { + uint8 n = op_read(r[HL]); + bool c = n & 0x01; + n >>= 1; + op_write(r[HL], n); + r.f.z = n == 0; + r.f.n = 0; + r.f.h = 0; + r.f.c = c; +} + +//single-bit commands + +template void CPU::op_bit_n_r() { + r.f.z = (r[x] & (1 << b)) == 0; + r.f.n = 0; + r.f.h = 1; +} + +template void CPU::op_bit_n_hl() { + uint8 n = op_read(r[HL]); + r.f.z = (n & (1 << b)) == 0; + r.f.n = 0; + r.f.h = 1; +} + +template void CPU::op_set_n_r() { + r[x] |= 1 << b; +} + +template void CPU::op_set_n_hl() { + uint8 n = op_read(r[HL]); + n |= 1 << b; + op_write(r[HL], n); +} + +template void CPU::op_res_n_r() { + r[x] &= ~(1 << b); +} + +template void CPU::op_res_n_hl() { + uint8 n = op_read(r[HL]); + n &= ~(1 << b); + op_write(r[HL], n); +} + +//control commands + +void CPU::op_ccf() { + r.f.n = 0; + r.f.h = 0; + r.f.c = !r.f.c; +} + +void CPU::op_scf() { + r.f.n = 0; + r.f.h = 0; + r.f.c = 1; +} + +void CPU::op_nop() { +} + +void CPU::op_halt() { + status.halt = true; + while(status.halt == true) op_io(); +} + +void CPU::op_stop() { + if(status.speed_switch) { + status.speed_switch = 0; + status.speed_double ^= 1; + frequency = 4 * 1024 * 1024; + if(status.speed_double) frequency *= 2; + return; + } + status.stop = true; + while(status.stop == true) op_io(); +} + +void CPU::op_di() { + status.ime = 0; +} + +void CPU::op_ei() { + status.ei = true; +//status.ime = 1; +} + +//jump commands + +void CPU::op_jp_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + r[PC] = (hi << 8) | (lo << 0); + op_io(); +} + +void CPU::op_jp_hl() { + r[PC] = r[HL]; +} + +template void CPU::op_jp_f_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + if(r.f[x] == y) { + r[PC] = (hi << 8) | (lo << 0); + op_io(); + } +} + +void CPU::op_jr_n() { + int8 n = op_read(r[PC]++); + r[PC] += n; + op_io(); +} + +template void CPU::op_jr_f_n() { + int8 n = op_read(r[PC]++); + if(r.f[x] == y) { + r[PC] += n; + op_io(); + } +} + +void CPU::op_call_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = (hi << 8) | (lo << 0); + op_io(); +} + +template void CPU::op_call_f_nn() { + uint8 lo = op_read(r[PC]++); + uint8 hi = op_read(r[PC]++); + if(r.f[x] == y) { + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = (hi << 8) | (lo << 0); + op_io(); + } +} + +void CPU::op_ret() { + uint8 lo = op_read(r[SP]++); + uint8 hi = op_read(r[SP]++); + r[PC] = (hi << 8) | (lo << 0); + op_io(); +} + +template void CPU::op_ret_f() { + op_io(); + if(r.f[x] == y) { + uint8 lo = op_read(r[SP]++); + uint8 hi = op_read(r[SP]++); + r[PC] = (hi << 8) | (lo << 0); + op_io(); + } +} + +void CPU::op_reti() { + uint8 lo = op_read(r[SP]++); + uint8 hi = op_read(r[SP]++); + r[PC] = (hi << 8) | (lo << 0); + op_io(); + status.ime = 1; +} + +template void CPU::op_rst_n() { + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = n; + op_io(); +} + +#endif diff --git a/gameboy/cpu/core/core.hpp b/gameboy/cpu/core/core.hpp new file mode 100755 index 00000000..85ebeb1d --- /dev/null +++ b/gameboy/cpu/core/core.hpp @@ -0,0 +1,145 @@ +#include "registers.hpp" +void (CPU::*opcode_table[256])(); +void (CPU::*opcode_table_cb[256])(); +void initialize_opcode_table(); + +void op_xx(); +void op_cb(); + +//8-bit load commands +template void op_ld_r_r(); +template void op_ld_r_n(); +template void op_ld_r_hl(); +template void op_ld_hl_r(); +void op_ld_hl_n(); +template void op_ld_a_rr(); +void op_ld_a_nn(); +template void op_ld_rr_a(); +void op_ld_nn_a(); +void op_ld_a_ffn(); +void op_ld_ffn_a(); +void op_ld_a_ffc(); +void op_ld_ffc_a(); +void op_ldi_hl_a(); +void op_ldi_a_hl(); +void op_ldd_hl_a(); +void op_ldd_a_hl(); + +//16-bit load commands +template void op_ld_rr_nn(); +void op_ld_nn_sp(); +void op_ld_sp_hl(); +template void op_push_rr(); +template void op_pop_rr(); + +//8-bit arithmetic commands +void opi_add_a(uint8 x); +template void op_add_a_r(); +void op_add_a_n(); +void op_add_a_hl(); + +void opi_adc_a(uint8 x); +template void op_adc_a_r(); +void op_adc_a_n(); +void op_adc_a_hl(); + +void opi_sub_a(uint8 x); +template void op_sub_a_r(); +void op_sub_a_n(); +void op_sub_a_hl(); + +void opi_sbc_a(uint8 x); +template void op_sbc_a_r(); +void op_sbc_a_n(); +void op_sbc_a_hl(); + +void opi_and_a(uint8 x); +template void op_and_a_r(); +void op_and_a_n(); +void op_and_a_hl(); + +void opi_xor_a(uint8 x); +template void op_xor_a_r(); +void op_xor_a_n(); +void op_xor_a_hl(); + +void opi_or_a(uint8 x); +template void op_or_a_r(); +void op_or_a_n(); +void op_or_a_hl(); + +void opi_cp_a(uint8 x); +template void op_cp_a_r(); +void op_cp_a_n(); +void op_cp_a_hl(); + +template void op_inc_r(); +void op_inc_hl(); +template void op_dec_r(); +void op_dec_hl(); +void op_daa(); +void op_cpl(); + +//16-bit arithmetic commands +template void op_add_hl_rr(); +template void op_inc_rr(); +template void op_dec_rr(); +void op_add_sp_n(); +void op_ld_hl_sp_n(); + +//rotate/shift commands +void op_rlca(); +void op_rla(); +void op_rrca(); +void op_rra(); +template void op_rlc_r(); +void op_rlc_hl(); +template void op_rl_r(); +void op_rl_hl(); +template void op_rrc_r(); +void op_rrc_hl(); +template void op_rr_r(); +void op_rr_hl(); +template void op_sla_r(); +void op_sla_hl(); +template void op_swap_r(); +void op_swap_hl(); +template void op_sra_r(); +void op_sra_hl(); +template void op_srl_r(); +void op_srl_hl(); + +//single-bit commands +template void op_bit_n_r(); +template void op_bit_n_hl(); +template void op_set_n_r(); +template void op_set_n_hl(); +template void op_res_n_r(); +template void op_res_n_hl(); + +//control commands +void op_ccf(); +void op_scf(); +void op_nop(); +void op_halt(); +void op_stop(); +void op_di(); +void op_ei(); + +//jump commands +void op_jp_nn(); +void op_jp_hl(); +template void op_jp_f_nn(); +void op_jr_n(); +template void op_jr_f_n(); +void op_call_nn(); +template void op_call_f_nn(); +void op_ret(); +template void op_ret_f(); +void op_reti(); +template void op_rst_n(); + +//disassembler.cpp +string disassemble(uint16 pc); +string disassemble_opcode(uint16 pc); +string disassemble_opcode_cb(uint16 pc); diff --git a/gameboy/cpu/core/disassembler.cpp b/gameboy/cpu/core/disassembler.cpp new file mode 100755 index 00000000..dbcee7ee --- /dev/null +++ b/gameboy/cpu/core/disassembler.cpp @@ -0,0 +1,560 @@ +#ifdef CPU_CPP + +string CPU::disassemble(uint16 pc) { + char output[80]; + memset(output, ' ', sizeof output); + output[79] = 0; + + string opcode = disassemble_opcode(pc); + string registers = { + " AF:", hex<4>(r[AF]), + " BC:", hex<4>(r[BC]), + " DE:", hex<4>(r[DE]), + " HL:", hex<4>(r[HL]), + " SP:", hex<4>(r[SP]) + }; + + memcpy(output + 0, hex<4>(pc), 4); + memcpy(output + 6, opcode, opcode.length()); + memcpy(output + 23, registers, registers.length()); + output[63] = 0; + return output; +} + +string CPU::disassemble_opcode(uint16 pc) { + uint8 opcode = bus.read(pc); + uint8 p0 = bus.read(pc + 1); + uint8 p1 = bus.read(pc + 2); + uint8 p2 = bus.read(pc + 3); + + switch(opcode) { + case 0x00: return { "nop" }; + case 0x01: return { "ld bc,$", hex<2>(p1), hex<2>(p0) }; + case 0x02: return { "ld (bc),a" }; + case 0x03: return { "inc bc" }; + case 0x04: return { "inc b" }; + case 0x05: return { "dec b" }; + case 0x06: return { "ld b,$", hex<2>(p0) }; + case 0x07: return { "rlc a" }; + case 0x08: return { "ld ($", hex<2>(p1), hex<2>(p0), "),sp" }; + case 0x09: return { "add hl,bc" }; + case 0x0a: return { "ld a,(bc)" }; + case 0x0b: return { "dec bc" }; + case 0x0c: return { "inc c" }; + case 0x0d: return { "dec c" }; + case 0x0e: return { "ld c,$", hex<2>(p0) }; + case 0x0f: return { "rrc a" }; + case 0x10: return { "stop" }; + case 0x11: return { "ld de,$", hex<2>(p1), hex<2>(p0) }; + case 0x12: return { "ld (de),a" }; + case 0x13: return { "inc de" }; + case 0x14: return { "inc d" }; + case 0x15: return { "dec d" }; + case 0x16: return { "ld d,$", hex<2>(p0) }; + case 0x17: return { "rl a" }; + case 0x18: return { "jr $", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x19: return { "add hl,de" }; + case 0x1a: return { "ld a,(de)" }; + case 0x1b: return { "dec de" }; + case 0x1c: return { "inc e" }; + case 0x1d: return { "dec e" }; + case 0x1e: return { "ld e,$", hex<2>(p0) }; + case 0x1f: return { "rr a" }; + case 0x20: return { "jr nz,$", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x21: return { "ld hl,$", hex<2>(p1), hex<2>(p0) }; + case 0x22: return { "ldi (hl),a" }; + case 0x23: return { "inc hl" }; + case 0x24: return { "inc h" }; + case 0x25: return { "dec h" }; + case 0x26: return { "ld h,$", hex<2>(p0) }; + case 0x27: return { "daa" }; + case 0x28: return { "jr z,$", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x29: return { "add hl,hl" }; + case 0x2a: return { "ldi a,(hl)" }; + case 0x2b: return { "dec hl" }; + case 0x2c: return { "inc l" }; + case 0x2d: return { "dec l" }; + case 0x2e: return { "ld l,$", hex<2>(p0) }; + case 0x2f: return { "cpl" }; + case 0x30: return { "jr nc,$", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x31: return { "ld sp,$", hex<2>(p1), hex<2>(p0) }; + case 0x32: return { "ldd (hl),a" }; + case 0x33: return { "inc sp" }; + case 0x34: return { "inc (hl)" }; + case 0x35: return { "dec (hl)" }; + case 0x36: return { "ld (hl),$", hex<2>(p0) }; + case 0x37: return { "scf" }; + case 0x38: return { "jr c,$", hex<4>(r[PC] + 2 + (int8)p0) }; + case 0x39: return { "add hl,sp" }; + case 0x3a: return { "ldd a,(hl)" }; + case 0x3b: return { "dec sp" }; + case 0x3c: return { "inc a" }; + case 0x3d: return { "dec a" }; + case 0x3e: return { "ld a,$", hex<2>(p0) }; + case 0x3f: return { "ccf" }; + case 0x40: return { "ld b,b" }; + case 0x41: return { "ld b,c" }; + case 0x42: return { "ld b,d" }; + case 0x43: return { "ld b,e" }; + case 0x44: return { "ld b,h" }; + case 0x45: return { "ld b,l" }; + case 0x46: return { "ld b,(hl)" }; + case 0x47: return { "ld b,a" }; + case 0x48: return { "ld c,b" }; + case 0x49: return { "ld c,c" }; + case 0x4a: return { "ld c,d" }; + case 0x4b: return { "ld c,e" }; + case 0x4c: return { "ld c,h" }; + case 0x4d: return { "ld c,l" }; + case 0x4e: return { "ld c,(hl)" }; + case 0x4f: return { "ld c,a" }; + case 0x50: return { "ld d,b" }; + case 0x51: return { "ld d,c" }; + case 0x52: return { "ld d,d" }; + case 0x53: return { "ld d,e" }; + case 0x54: return { "ld d,h" }; + case 0x55: return { "ld d,l" }; + case 0x56: return { "ld d,(hl)" }; + case 0x57: return { "ld d,a" }; + case 0x58: return { "ld e,b" }; + case 0x59: return { "ld e,c" }; + case 0x5a: return { "ld e,d" }; + case 0x5b: return { "ld e,e" }; + case 0x5c: return { "ld e,h" }; + case 0x5d: return { "ld e,l" }; + case 0x5e: return { "ld e,(hl)" }; + case 0x5f: return { "ld e,a" }; + case 0x60: return { "ld h,b" }; + case 0x61: return { "ld h,c" }; + case 0x62: return { "ld h,d" }; + case 0x63: return { "ld h,e" }; + case 0x64: return { "ld h,h" }; + case 0x65: return { "ld h,l" }; + case 0x66: return { "ld h,(hl)" }; + case 0x67: return { "ld h,a" }; + case 0x68: return { "ld l,b" }; + case 0x69: return { "ld l,c" }; + case 0x6a: return { "ld l,d" }; + case 0x6b: return { "ld l,e" }; + case 0x6c: return { "ld l,h" }; + case 0x6d: return { "ld l,l" }; + case 0x6e: return { "ld l,(hl)" }; + case 0x6f: return { "ld l,a" }; + case 0x70: return { "ld (hl),b" }; + case 0x71: return { "ld (hl),c" }; + case 0x72: return { "ld (hl),d" }; + case 0x73: return { "ld (hl),e" }; + case 0x74: return { "ld (hl),h" }; + case 0x75: return { "ld (hl),l" }; + case 0x76: return { "halt" }; + case 0x77: return { "ld (hl),a" }; + case 0x78: return { "ld a,b" }; + case 0x79: return { "ld a,c" }; + case 0x7a: return { "ld a,d" }; + case 0x7b: return { "ld a,e" }; + case 0x7c: return { "ld a,h" }; + case 0x7d: return { "ld a,l" }; + case 0x7e: return { "ld a,(hl)" }; + case 0x7f: return { "ld a,a" }; + case 0x80: return { "add a,b" }; + case 0x81: return { "add a,c" }; + case 0x82: return { "add a,d" }; + case 0x83: return { "add a,e" }; + case 0x84: return { "add a,h" }; + case 0x85: return { "add a,l" }; + case 0x86: return { "add a,(hl)" }; + case 0x87: return { "add a,a" }; + case 0x88: return { "adc a,b" }; + case 0x89: return { "adc a,c" }; + case 0x8a: return { "adc a,d" }; + case 0x8b: return { "adc a,e" }; + case 0x8c: return { "adc a,h" }; + case 0x8d: return { "adc a,l" }; + case 0x8e: return { "adc a,(hl)" }; + case 0x8f: return { "adc a,a" }; + case 0x90: return { "sub a,b" }; + case 0x91: return { "sub a,c" }; + case 0x92: return { "sub a,d" }; + case 0x93: return { "sub a,e" }; + case 0x94: return { "sub a,h" }; + case 0x95: return { "sub a,l" }; + case 0x96: return { "sub a,(hl)" }; + case 0x97: return { "sub a,a" }; + case 0x98: return { "sbc a,b" }; + case 0x99: return { "sbc a,c" }; + case 0x9a: return { "sbc a,d" }; + case 0x9b: return { "sbc a,e" }; + case 0x9c: return { "sbc a,h" }; + case 0x9d: return { "sbc a,l" }; + case 0x9e: return { "sbc a,(hl)" }; + case 0x9f: return { "sbc a,a" }; + case 0xa0: return { "and a,b" }; + case 0xa1: return { "and a,c" }; + case 0xa2: return { "and a,d" }; + case 0xa3: return { "and a,e" }; + case 0xa4: return { "and a,h" }; + case 0xa5: return { "and a,l" }; + case 0xa6: return { "and a,(hl)" }; + case 0xa7: return { "and a,a" }; + case 0xa8: return { "xor a,b" }; + case 0xa9: return { "xor a,c" }; + case 0xaa: return { "xor a,d" }; + case 0xab: return { "xor a,e" }; + case 0xac: return { "xor a,h" }; + case 0xad: return { "xor a,l" }; + case 0xae: return { "xor a,(hl)" }; + case 0xaf: return { "xor a,a" }; + case 0xb0: return { "or a,b" }; + case 0xb1: return { "or a,c" }; + case 0xb2: return { "or a,d" }; + case 0xb3: return { "or a,e" }; + case 0xb4: return { "or a,h" }; + case 0xb5: return { "or a,l" }; + case 0xb6: return { "or a,(hl)" }; + case 0xb7: return { "or a,a" }; + case 0xb8: return { "cp a,b" }; + case 0xb9: return { "cp a,c" }; + case 0xba: return { "cp a,d" }; + case 0xbb: return { "cp a,e" }; + case 0xbc: return { "cp a,h" }; + case 0xbd: return { "cp a,l" }; + case 0xbe: return { "cp a,(hl)" }; + case 0xbf: return { "cp a,a" }; + case 0xc0: return { "ret nz" }; + case 0xc1: return { "pop bc" }; + case 0xc2: return { "jp nz,$", hex<2>(p1), hex<2>(p0) }; + case 0xc3: return { "jp $", hex<2>(p1), hex<2>(p0) }; + case 0xc4: return { "call nz,$", hex<2>(p1), hex<2>(p0) }; + case 0xc5: return { "push bc" }; + case 0xc6: return { "add a,$", hex<2>(p0) }; + case 0xc7: return { "rst $0000" }; + case 0xc8: return { "ret z" }; + case 0xc9: return { "ret" }; + case 0xca: return { "jp z,$", hex<2>(p1), hex<2>(p0) }; + case 0xcb: return disassemble_opcode_cb(pc + 1); + case 0xcc: return { "call z,$", hex<2>(p1), hex<2>(p0) }; + case 0xcd: return { "call $", hex<2>(p1), hex<2>(p0) }; + case 0xce: return { "adc a,$", hex<2>(p0) }; + case 0xcf: return { "rst $0008" }; + case 0xd0: return { "ret nc" }; + case 0xd1: return { "pop de" }; + case 0xd2: return { "jp nc,$", hex<2>(p1), hex<2>(p0) }; + case 0xd3: return { "xx" }; + case 0xd4: return { "call nc,$", hex<2>(p1), hex<2>(p0) }; + case 0xd5: return { "push de" }; + case 0xd6: return { "sub a,$", hex<2>(p0) }; + case 0xd7: return { "rst $0010" }; + case 0xd8: return { "ret c" }; + case 0xd9: return { "reti" }; + case 0xda: return { "jp c,$", hex<2>(p1), hex<2>(p0) }; + case 0xdb: return { "xx" }; + case 0xdc: return { "call c,$", hex<2>(p1), hex<2>(p0) }; + case 0xdd: return { "xx" }; + case 0xde: return { "sbc a,$", hex<2>(p0) }; + case 0xdf: return { "rst $0018" }; + case 0xe0: return { "ld ($ff", hex<2>(p0), "),a" }; + case 0xe1: return { "pop hl" }; + case 0xe2: return { "ld ($ff00+c),a" }; + case 0xe3: return { "xx" }; + case 0xe4: return { "xx" }; + case 0xe5: return { "push hl" }; + case 0xe6: return { "and a,$", hex<2>(p0) }; + case 0xe7: return { "rst $0020" }; + case 0xe8: return { "add sp,$", hex<4>((int8)p0) }; + case 0xe9: return { "jp hl" }; + case 0xea: return { "ld ($", hex<2>(p1), hex<2>(p0), "),a" }; + case 0xeb: return { "xx" }; + case 0xec: return { "xx" }; + case 0xed: return { "xx" }; + case 0xee: return { "xor a,$", hex<2>(p0) }; + case 0xef: return { "rst $0028" }; + case 0xf0: return { "ld a,($ff", hex<2>(p0), ")" }; + case 0xf1: return { "pop af" }; + case 0xf2: return { "ld a,($ff00+c)" }; + case 0xf3: return { "di" }; + case 0xf4: return { "xx" }; + case 0xf5: return { "push af" }; + case 0xf6: return { "or a,$", hex<2>(p0) }; + case 0xf7: return { "rst $0030" }; + case 0xf8: return { "ld hl,sp+$", hex<4>((int8)p0) }; + case 0xf9: return { "ld sp,hl" }; + case 0xfa: return { "ld a,($", hex<2>(p1), hex<2>(p0), ")" }; + case 0xfb: return { "ei" }; + case 0xfc: return { "xx" }; + case 0xfd: return { "xx" }; + case 0xfe: return { "cp a,$", hex<2>(p0) }; + case 0xff: return { "rst $0038" }; + } + + return ""; +} + +string CPU::disassemble_opcode_cb(uint16 pc) { + uint8 opcode = bus.read(pc); + uint8 p0 = bus.read(pc + 1); + uint8 p1 = bus.read(pc + 2); + uint8 p2 = bus.read(pc + 3); + + switch(opcode) { + case 0x00: return { "rlc b" }; + case 0x01: return { "rlc c" }; + case 0x02: return { "rlc d" }; + case 0x03: return { "rlc e" }; + case 0x04: return { "rlc h" }; + case 0x05: return { "rlc l" }; + case 0x06: return { "rlc (hl)" }; + case 0x07: return { "rlc a" }; + case 0x08: return { "rrc b" }; + case 0x09: return { "rrc c" }; + case 0x0a: return { "rrc d" }; + case 0x0b: return { "rrc e" }; + case 0x0c: return { "rrc h" }; + case 0x0d: return { "rrc l" }; + case 0x0e: return { "rrc (hl)" }; + case 0x0f: return { "rrc a" }; + case 0x10: return { "rl b" }; + case 0x11: return { "rl c" }; + case 0x12: return { "rl d" }; + case 0x13: return { "rl e" }; + case 0x14: return { "rl h" }; + case 0x15: return { "rl l" }; + case 0x16: return { "rl (hl)" }; + case 0x17: return { "rl a" }; + case 0x18: return { "rr b" }; + case 0x19: return { "rr c" }; + case 0x1a: return { "rr d" }; + case 0x1b: return { "rr e" }; + case 0x1c: return { "rr h" }; + case 0x1d: return { "rr l" }; + case 0x1e: return { "rr (hl)" }; + case 0x1f: return { "rr a" }; + case 0x20: return { "sla b" }; + case 0x21: return { "sla c" }; + case 0x22: return { "sla d" }; + case 0x23: return { "sla e" }; + case 0x24: return { "sla h" }; + case 0x25: return { "sla l" }; + case 0x26: return { "sla (hl)" }; + case 0x27: return { "sla a" }; + case 0x28: return { "sra b" }; + case 0x29: return { "sra c" }; + case 0x2a: return { "sra d" }; + case 0x2b: return { "sra e" }; + case 0x2c: return { "sra h" }; + case 0x2d: return { "sra l" }; + case 0x2e: return { "sra (hl)" }; + case 0x2f: return { "sra a" }; + case 0x30: return { "swap b" }; + case 0x31: return { "swap c" }; + case 0x32: return { "swap d" }; + case 0x33: return { "swap e" }; + case 0x34: return { "swap h" }; + case 0x35: return { "swap l" }; + case 0x36: return { "swap (hl)" }; + case 0x37: return { "swap a" }; + case 0x38: return { "srl b" }; + case 0x39: return { "srl c" }; + case 0x3a: return { "srl d" }; + case 0x3b: return { "srl e" }; + case 0x3c: return { "srl h" }; + case 0x3d: return { "srl l" }; + case 0x3e: return { "srl (hl)" }; + case 0x3f: return { "srl a" }; + case 0x40: return { "bit 0,b" }; + case 0x41: return { "bit 0,c" }; + case 0x42: return { "bit 0,d" }; + case 0x43: return { "bit 0,e" }; + case 0x44: return { "bit 0,h" }; + case 0x45: return { "bit 0,l" }; + case 0x46: return { "bit 0,(hl)" }; + case 0x47: return { "bit 0,a" }; + case 0x48: return { "bit 1,b" }; + case 0x49: return { "bit 1,c" }; + case 0x4a: return { "bit 1,d" }; + case 0x4b: return { "bit 1,e" }; + case 0x4c: return { "bit 1,h" }; + case 0x4d: return { "bit 1,l" }; + case 0x4e: return { "bit 1,(hl)" }; + case 0x4f: return { "bit 1,a" }; + case 0x50: return { "bit 2,b" }; + case 0x51: return { "bit 2,c" }; + case 0x52: return { "bit 2,d" }; + case 0x53: return { "bit 2,e" }; + case 0x54: return { "bit 2,h" }; + case 0x55: return { "bit 2,l" }; + case 0x56: return { "bit 2,(hl)" }; + case 0x57: return { "bit 2,a" }; + case 0x58: return { "bit 3,b" }; + case 0x59: return { "bit 3,c" }; + case 0x5a: return { "bit 3,d" }; + case 0x5b: return { "bit 3,e" }; + case 0x5c: return { "bit 3,h" }; + case 0x5d: return { "bit 3,l" }; + case 0x5e: return { "bit 3,(hl)" }; + case 0x5f: return { "bit 3,a" }; + case 0x60: return { "bit 4,b" }; + case 0x61: return { "bit 4,c" }; + case 0x62: return { "bit 4,d" }; + case 0x63: return { "bit 4,e" }; + case 0x64: return { "bit 4,h" }; + case 0x65: return { "bit 4,l" }; + case 0x66: return { "bit 4,(hl)" }; + case 0x67: return { "bit 4,a" }; + case 0x68: return { "bit 5,b" }; + case 0x69: return { "bit 5,c" }; + case 0x6a: return { "bit 5,d" }; + case 0x6b: return { "bit 5,e" }; + case 0x6c: return { "bit 5,h" }; + case 0x6d: return { "bit 5,l" }; + case 0x6e: return { "bit 5,(hl)" }; + case 0x6f: return { "bit 5,a" }; + case 0x70: return { "bit 6,b" }; + case 0x71: return { "bit 6,c" }; + case 0x72: return { "bit 6,d" }; + case 0x73: return { "bit 6,e" }; + case 0x74: return { "bit 6,h" }; + case 0x75: return { "bit 6,l" }; + case 0x76: return { "bit 6,(hl)" }; + case 0x77: return { "bit 6,a" }; + case 0x78: return { "bit 7,b" }; + case 0x79: return { "bit 7,c" }; + case 0x7a: return { "bit 7,d" }; + case 0x7b: return { "bit 7,e" }; + case 0x7c: return { "bit 7,h" }; + case 0x7d: return { "bit 7,l" }; + case 0x7e: return { "bit 7,(hl)" }; + case 0x7f: return { "bit 7,a" }; + case 0x80: return { "res 0,b" }; + case 0x81: return { "res 0,c" }; + case 0x82: return { "res 0,d" }; + case 0x83: return { "res 0,e" }; + case 0x84: return { "res 0,h" }; + case 0x85: return { "res 0,l" }; + case 0x86: return { "res 0,(hl)" }; + case 0x87: return { "res 0,a" }; + case 0x88: return { "res 1,b" }; + case 0x89: return { "res 1,c" }; + case 0x8a: return { "res 1,d" }; + case 0x8b: return { "res 1,e" }; + case 0x8c: return { "res 1,h" }; + case 0x8d: return { "res 1,l" }; + case 0x8e: return { "res 1,(hl)" }; + case 0x8f: return { "res 1,a" }; + case 0x90: return { "res 2,b" }; + case 0x91: return { "res 2,c" }; + case 0x92: return { "res 2,d" }; + case 0x93: return { "res 2,e" }; + case 0x94: return { "res 2,h" }; + case 0x95: return { "res 2,l" }; + case 0x96: return { "res 2,(hl)" }; + case 0x97: return { "res 2,a" }; + case 0x98: return { "res 3,b" }; + case 0x99: return { "res 3,c" }; + case 0x9a: return { "res 3,d" }; + case 0x9b: return { "res 3,e" }; + case 0x9c: return { "res 3,h" }; + case 0x9d: return { "res 3,l" }; + case 0x9e: return { "res 3,(hl)" }; + case 0x9f: return { "res 3,a" }; + case 0xa0: return { "res 4,b" }; + case 0xa1: return { "res 4,c" }; + case 0xa2: return { "res 4,d" }; + case 0xa3: return { "res 4,e" }; + case 0xa4: return { "res 4,h" }; + case 0xa5: return { "res 4,l" }; + case 0xa6: return { "res 4,(hl)" }; + case 0xa7: return { "res 4,a" }; + case 0xa8: return { "res 5,b" }; + case 0xa9: return { "res 5,c" }; + case 0xaa: return { "res 5,d" }; + case 0xab: return { "res 5,e" }; + case 0xac: return { "res 5,h" }; + case 0xad: return { "res 5,l" }; + case 0xae: return { "res 5,(hl)" }; + case 0xaf: return { "res 5,a" }; + case 0xb0: return { "res 6,b" }; + case 0xb1: return { "res 6,c" }; + case 0xb2: return { "res 6,d" }; + case 0xb3: return { "res 6,e" }; + case 0xb4: return { "res 6,h" }; + case 0xb5: return { "res 6,l" }; + case 0xb6: return { "res 6,(hl)" }; + case 0xb7: return { "res 6,a" }; + case 0xb8: return { "res 7,b" }; + case 0xb9: return { "res 7,c" }; + case 0xba: return { "res 7,d" }; + case 0xbb: return { "res 7,e" }; + case 0xbc: return { "res 7,h" }; + case 0xbd: return { "res 7,l" }; + case 0xbe: return { "res 7,(hl)" }; + case 0xbf: return { "res 7,a" }; + case 0xc0: return { "set 0,b" }; + case 0xc1: return { "set 0,c" }; + case 0xc2: return { "set 0,d" }; + case 0xc3: return { "set 0,e" }; + case 0xc4: return { "set 0,h" }; + case 0xc5: return { "set 0,l" }; + case 0xc6: return { "set 0,(hl)" }; + case 0xc7: return { "set 0,a" }; + case 0xc8: return { "set 1,b" }; + case 0xc9: return { "set 1,c" }; + case 0xca: return { "set 1,d" }; + case 0xcb: return { "set 1,e" }; + case 0xcc: return { "set 1,h" }; + case 0xcd: return { "set 1,l" }; + case 0xce: return { "set 1,(hl)" }; + case 0xcf: return { "set 1,a" }; + case 0xd0: return { "set 2,b" }; + case 0xd1: return { "set 2,c" }; + case 0xd2: return { "set 2,d" }; + case 0xd3: return { "set 2,e" }; + case 0xd4: return { "set 2,h" }; + case 0xd5: return { "set 2,l" }; + case 0xd6: return { "set 2,(hl)" }; + case 0xd7: return { "set 2,a" }; + case 0xd8: return { "set 3,b" }; + case 0xd9: return { "set 3,c" }; + case 0xda: return { "set 3,d" }; + case 0xdb: return { "set 3,e" }; + case 0xdc: return { "set 3,h" }; + case 0xdd: return { "set 3,l" }; + case 0xde: return { "set 3,(hl)" }; + case 0xdf: return { "set 3,a" }; + case 0xe0: return { "set 4,b" }; + case 0xe1: return { "set 4,c" }; + case 0xe2: return { "set 4,d" }; + case 0xe3: return { "set 4,e" }; + case 0xe4: return { "set 4,h" }; + case 0xe5: return { "set 4,l" }; + case 0xe6: return { "set 4,(hl)" }; + case 0xe7: return { "set 4,a" }; + case 0xe8: return { "set 5,b" }; + case 0xe9: return { "set 5,c" }; + case 0xea: return { "set 5,d" }; + case 0xeb: return { "set 5,e" }; + case 0xec: return { "set 5,h" }; + case 0xed: return { "set 5,l" }; + case 0xee: return { "set 5,(hl)" }; + case 0xef: return { "set 5,a" }; + case 0xf0: return { "set 6,b" }; + case 0xf1: return { "set 6,c" }; + case 0xf2: return { "set 6,d" }; + case 0xf3: return { "set 6,e" }; + case 0xf4: return { "set 6,h" }; + case 0xf5: return { "set 6,l" }; + case 0xf6: return { "set 6,(hl)" }; + case 0xf7: return { "set 6,a" }; + case 0xf8: return { "set 7,b" }; + case 0xf9: return { "set 7,c" }; + case 0xfa: return { "set 7,d" }; + case 0xfb: return { "set 7,e" }; + case 0xfc: return { "set 7,h" }; + case 0xfd: return { "set 7,l" }; + case 0xfe: return { "set 7,(hl)" }; + case 0xff: return { "set 7,a" }; + } + + return ""; +} + +#endif diff --git a/gameboy/cpu/core/registers.hpp b/gameboy/cpu/core/registers.hpp new file mode 100755 index 00000000..fbbcbd80 --- /dev/null +++ b/gameboy/cpu/core/registers.hpp @@ -0,0 +1,101 @@ +enum { + A, F, AF, + B, C, BC, + D, E, DE, + H, L, HL, + SP, PC, +}; + +enum { + ZF, NF, HF, CF, +}; + +//register base class +//the idea here is to have all registers derive from a single base class. +//this allows construction of opcodes that can take any register as input or output, +//despite the fact that behind-the-scenes, special handling is done for eg: F, AF, HL, etc. +//registers can also be chained together: eg af = 0x0000 writes both a and f. +struct Register { + virtual operator unsigned() const = 0; + virtual unsigned operator=(unsigned x) = 0; + Register& operator=(const Register &x) { operator=((unsigned)x); return *this; } + + unsigned operator++(int) { unsigned r = *this; operator=(*this + 1); return r; } + unsigned operator--(int) { unsigned r = *this; operator=(*this - 1); return r; } + unsigned operator++() { return operator=(*this + 1); } + unsigned operator--() { return operator=(*this - 1); } + + unsigned operator |=(unsigned x) { return operator=(*this | x); } + unsigned operator ^=(unsigned x) { return operator=(*this ^ x); } + unsigned operator &=(unsigned x) { return operator=(*this & x); } + + unsigned operator<<=(unsigned x) { return operator=(*this << x); } + unsigned operator>>=(unsigned x) { return operator=(*this >> x); } + + unsigned operator +=(unsigned x) { return operator=(*this + x); } + unsigned operator -=(unsigned x) { return operator=(*this - x); } + unsigned operator *=(unsigned x) { return operator=(*this * x); } + unsigned operator /=(unsigned x) { return operator=(*this / x); } + unsigned operator %=(unsigned x) { return operator=(*this % x); } +}; + +struct Register8 : Register { + uint8 data; + operator unsigned() const { return data; } + unsigned operator=(unsigned x) { return data = x; } +}; + +struct RegisterF : Register { + bool z, n, h, c; + operator unsigned() const { return (z << 7) | (n << 6) | (h << 5) | (c << 4); } + unsigned operator=(unsigned x) { z = x & 0x80; n = x & 0x40; h = x & 0x20; c = x & 0x10; return *this; } + bool& operator[](unsigned r) { + static bool* table[] = { &z, &n, &h, &c }; + return *table[r]; + } +}; + +struct Register16 : Register { + uint16 data; + operator unsigned() const { return data; } + unsigned operator=(unsigned x) { return data = x; } +}; + +struct RegisterAF : Register { + Register8 &hi; + RegisterF &lo; + operator unsigned() const { return (hi << 8) | (lo << 0); } + unsigned operator=(unsigned x) { hi = x >> 8; lo = x >> 0; return *this; } + RegisterAF(Register8 &hi, RegisterF &lo) : hi(hi), lo(lo) {} +}; + +struct RegisterW : Register { + Register8 &hi, &lo; + operator unsigned() const { return (hi << 8) | (lo << 0); } + unsigned operator=(unsigned x) { hi = x >> 8; lo = x >> 0; return *this; } + RegisterW(Register8 &hi, Register8 &lo) : hi(hi), lo(lo) {} +}; + +struct Registers { + Register8 a; + RegisterF f; + RegisterAF af; + Register8 b; + Register8 c; + RegisterW bc; + Register8 d; + Register8 e; + RegisterW de; + Register8 h; + Register8 l; + RegisterW hl; + Register16 sp; + Register16 pc; + + Register& operator[](unsigned r) { + static Register* table[] = { &a, &f, &af, &b, &c, &bc, &d, &e, &de, &h, &l, &hl, &sp, &pc }; + return *table[r]; + } + + Registers() : af(a, f), bc(b, c), de(d, e), hl(h, l) {} +} r; diff --git a/gameboy/cpu/core/table.cpp b/gameboy/cpu/core/table.cpp new file mode 100755 index 00000000..fa2f1112 --- /dev/null +++ b/gameboy/cpu/core/table.cpp @@ -0,0 +1,519 @@ +#ifdef CPU_CPP + +void CPU::initialize_opcode_table() { + opcode_table[0x00] = &CPU::op_nop; + opcode_table[0x01] = &CPU::op_ld_rr_nn; + opcode_table[0x02] = &CPU::op_ld_rr_a; + opcode_table[0x03] = &CPU::op_inc_rr; + opcode_table[0x04] = &CPU::op_inc_r; + opcode_table[0x05] = &CPU::op_dec_r; + opcode_table[0x06] = &CPU::op_ld_r_n; + opcode_table[0x07] = &CPU::op_rlca; + opcode_table[0x08] = &CPU::op_ld_nn_sp; + opcode_table[0x09] = &CPU::op_add_hl_rr; + opcode_table[0x0a] = &CPU::op_ld_a_rr; + opcode_table[0x0b] = &CPU::op_dec_rr; + opcode_table[0x0c] = &CPU::op_inc_r; + opcode_table[0x0d] = &CPU::op_dec_r; + opcode_table[0x0e] = &CPU::op_ld_r_n; + opcode_table[0x0f] = &CPU::op_rrca; + opcode_table[0x10] = &CPU::op_stop; + opcode_table[0x11] = &CPU::op_ld_rr_nn; + opcode_table[0x12] = &CPU::op_ld_rr_a; + opcode_table[0x13] = &CPU::op_inc_rr; + opcode_table[0x14] = &CPU::op_inc_r; + opcode_table[0x15] = &CPU::op_dec_r; + opcode_table[0x16] = &CPU::op_ld_r_n; + opcode_table[0x17] = &CPU::op_rla; + opcode_table[0x18] = &CPU::op_jr_n; + opcode_table[0x19] = &CPU::op_add_hl_rr; + opcode_table[0x1a] = &CPU::op_ld_a_rr; + opcode_table[0x1b] = &CPU::op_dec_rr; + opcode_table[0x1c] = &CPU::op_inc_r; + opcode_table[0x1d] = &CPU::op_dec_r; + opcode_table[0x1e] = &CPU::op_ld_r_n; + opcode_table[0x1f] = &CPU::op_rra; + opcode_table[0x20] = &CPU::op_jr_f_n; + opcode_table[0x21] = &CPU::op_ld_rr_nn; + opcode_table[0x22] = &CPU::op_ldi_hl_a; + opcode_table[0x23] = &CPU::op_inc_rr; + opcode_table[0x24] = &CPU::op_inc_r; + opcode_table[0x25] = &CPU::op_dec_r; + opcode_table[0x26] = &CPU::op_ld_r_n; + opcode_table[0x27] = &CPU::op_daa; + opcode_table[0x28] = &CPU::op_jr_f_n; + opcode_table[0x29] = &CPU::op_add_hl_rr; + opcode_table[0x2a] = &CPU::op_ldi_a_hl; + opcode_table[0x2b] = &CPU::op_dec_rr; + opcode_table[0x2c] = &CPU::op_inc_r; + opcode_table[0x2d] = &CPU::op_dec_r; + opcode_table[0x2e] = &CPU::op_ld_r_n; + opcode_table[0x2f] = &CPU::op_cpl; + opcode_table[0x30] = &CPU::op_jr_f_n; + opcode_table[0x31] = &CPU::op_ld_rr_nn; + opcode_table[0x32] = &CPU::op_ldd_hl_a; + opcode_table[0x33] = &CPU::op_inc_rr; + opcode_table[0x34] = &CPU::op_inc_hl; + opcode_table[0x35] = &CPU::op_dec_hl; + opcode_table[0x36] = &CPU::op_ld_hl_n; + opcode_table[0x37] = &CPU::op_scf; + opcode_table[0x38] = &CPU::op_jr_f_n; + opcode_table[0x39] = &CPU::op_add_hl_rr; + opcode_table[0x3a] = &CPU::op_ldd_a_hl; + opcode_table[0x3b] = &CPU::op_dec_rr; + opcode_table[0x3c] = &CPU::op_inc_r; + opcode_table[0x3d] = &CPU::op_dec_r; + opcode_table[0x3e] = &CPU::op_ld_r_n; + opcode_table[0x3f] = &CPU::op_ccf; + opcode_table[0x40] = &CPU::op_ld_r_r; + opcode_table[0x41] = &CPU::op_ld_r_r; + opcode_table[0x42] = &CPU::op_ld_r_r; + opcode_table[0x43] = &CPU::op_ld_r_r; + opcode_table[0x44] = &CPU::op_ld_r_r; + opcode_table[0x45] = &CPU::op_ld_r_r; + opcode_table[0x46] = &CPU::op_ld_r_hl; + opcode_table[0x47] = &CPU::op_ld_r_r; + opcode_table[0x48] = &CPU::op_ld_r_r; + opcode_table[0x49] = &CPU::op_ld_r_r; + opcode_table[0x4a] = &CPU::op_ld_r_r; + opcode_table[0x4b] = &CPU::op_ld_r_r; + opcode_table[0x4c] = &CPU::op_ld_r_r; + opcode_table[0x4d] = &CPU::op_ld_r_r; + opcode_table[0x4e] = &CPU::op_ld_r_hl; + opcode_table[0x4f] = &CPU::op_ld_r_r; + opcode_table[0x50] = &CPU::op_ld_r_r; + opcode_table[0x51] = &CPU::op_ld_r_r; + opcode_table[0x52] = &CPU::op_ld_r_r; + opcode_table[0x53] = &CPU::op_ld_r_r; + opcode_table[0x54] = &CPU::op_ld_r_r; + opcode_table[0x55] = &CPU::op_ld_r_r; + opcode_table[0x56] = &CPU::op_ld_r_hl; + opcode_table[0x57] = &CPU::op_ld_r_r; + opcode_table[0x58] = &CPU::op_ld_r_r; + opcode_table[0x59] = &CPU::op_ld_r_r; + opcode_table[0x5a] = &CPU::op_ld_r_r; + opcode_table[0x5b] = &CPU::op_ld_r_r; + opcode_table[0x5c] = &CPU::op_ld_r_r; + opcode_table[0x5d] = &CPU::op_ld_r_r; + opcode_table[0x5e] = &CPU::op_ld_r_hl; + opcode_table[0x5f] = &CPU::op_ld_r_r; + opcode_table[0x60] = &CPU::op_ld_r_r; + opcode_table[0x61] = &CPU::op_ld_r_r; + opcode_table[0x62] = &CPU::op_ld_r_r; + opcode_table[0x63] = &CPU::op_ld_r_r; + opcode_table[0x64] = &CPU::op_ld_r_r; + opcode_table[0x65] = &CPU::op_ld_r_r; + opcode_table[0x66] = &CPU::op_ld_r_hl; + opcode_table[0x67] = &CPU::op_ld_r_r; + opcode_table[0x68] = &CPU::op_ld_r_r; + opcode_table[0x69] = &CPU::op_ld_r_r; + opcode_table[0x6a] = &CPU::op_ld_r_r; + opcode_table[0x6b] = &CPU::op_ld_r_r; + opcode_table[0x6c] = &CPU::op_ld_r_r; + opcode_table[0x6d] = &CPU::op_ld_r_r; + opcode_table[0x6e] = &CPU::op_ld_r_hl; + opcode_table[0x6f] = &CPU::op_ld_r_r; + opcode_table[0x70] = &CPU::op_ld_hl_r; + opcode_table[0x71] = &CPU::op_ld_hl_r; + opcode_table[0x72] = &CPU::op_ld_hl_r; + opcode_table[0x73] = &CPU::op_ld_hl_r; + opcode_table[0x74] = &CPU::op_ld_hl_r; + opcode_table[0x75] = &CPU::op_ld_hl_r; + opcode_table[0x76] = &CPU::op_halt; + opcode_table[0x77] = &CPU::op_ld_hl_r; + opcode_table[0x78] = &CPU::op_ld_r_r; + opcode_table[0x79] = &CPU::op_ld_r_r; + opcode_table[0x7a] = &CPU::op_ld_r_r; + opcode_table[0x7b] = &CPU::op_ld_r_r; + opcode_table[0x7c] = &CPU::op_ld_r_r; + opcode_table[0x7d] = &CPU::op_ld_r_r; + opcode_table[0x7e] = &CPU::op_ld_r_hl; + opcode_table[0x7f] = &CPU::op_ld_r_r; + opcode_table[0x80] = &CPU::op_add_a_r; + opcode_table[0x81] = &CPU::op_add_a_r; + opcode_table[0x82] = &CPU::op_add_a_r; + opcode_table[0x83] = &CPU::op_add_a_r; + opcode_table[0x84] = &CPU::op_add_a_r; + opcode_table[0x85] = &CPU::op_add_a_r; + opcode_table[0x86] = &CPU::op_add_a_hl; + opcode_table[0x87] = &CPU::op_add_a_r; + opcode_table[0x88] = &CPU::op_adc_a_r; + opcode_table[0x89] = &CPU::op_adc_a_r; + opcode_table[0x8a] = &CPU::op_adc_a_r; + opcode_table[0x8b] = &CPU::op_adc_a_r; + opcode_table[0x8c] = &CPU::op_adc_a_r; + opcode_table[0x8d] = &CPU::op_adc_a_r; + opcode_table[0x8e] = &CPU::op_adc_a_hl; + opcode_table[0x8f] = &CPU::op_adc_a_r; + opcode_table[0x90] = &CPU::op_sub_a_r; + opcode_table[0x91] = &CPU::op_sub_a_r; + opcode_table[0x92] = &CPU::op_sub_a_r; + opcode_table[0x93] = &CPU::op_sub_a_r; + opcode_table[0x94] = &CPU::op_sub_a_r; + opcode_table[0x95] = &CPU::op_sub_a_r; + opcode_table[0x96] = &CPU::op_sub_a_hl; + opcode_table[0x97] = &CPU::op_sub_a_r; + opcode_table[0x98] = &CPU::op_sbc_a_r; + opcode_table[0x99] = &CPU::op_sbc_a_r; + opcode_table[0x9a] = &CPU::op_sbc_a_r; + opcode_table[0x9b] = &CPU::op_sbc_a_r; + opcode_table[0x9c] = &CPU::op_sbc_a_r; + opcode_table[0x9d] = &CPU::op_sbc_a_r; + opcode_table[0x9e] = &CPU::op_sbc_a_hl; + opcode_table[0x9f] = &CPU::op_sbc_a_r; + opcode_table[0xa0] = &CPU::op_and_a_r; + opcode_table[0xa1] = &CPU::op_and_a_r; + opcode_table[0xa2] = &CPU::op_and_a_r; + opcode_table[0xa3] = &CPU::op_and_a_r; + opcode_table[0xa4] = &CPU::op_and_a_r; + opcode_table[0xa5] = &CPU::op_and_a_r; + opcode_table[0xa6] = &CPU::op_and_a_hl; + opcode_table[0xa7] = &CPU::op_and_a_r; + opcode_table[0xa8] = &CPU::op_xor_a_r; + opcode_table[0xa9] = &CPU::op_xor_a_r; + opcode_table[0xaa] = &CPU::op_xor_a_r; + opcode_table[0xab] = &CPU::op_xor_a_r; + opcode_table[0xac] = &CPU::op_xor_a_r; + opcode_table[0xad] = &CPU::op_xor_a_r; + opcode_table[0xae] = &CPU::op_xor_a_hl; + opcode_table[0xaf] = &CPU::op_xor_a_r; + opcode_table[0xb0] = &CPU::op_or_a_r; + opcode_table[0xb1] = &CPU::op_or_a_r; + opcode_table[0xb2] = &CPU::op_or_a_r; + opcode_table[0xb3] = &CPU::op_or_a_r; + opcode_table[0xb4] = &CPU::op_or_a_r; + opcode_table[0xb5] = &CPU::op_or_a_r; + opcode_table[0xb6] = &CPU::op_or_a_hl; + opcode_table[0xb7] = &CPU::op_or_a_r; + opcode_table[0xb8] = &CPU::op_cp_a_r; + opcode_table[0xb9] = &CPU::op_cp_a_r; + opcode_table[0xba] = &CPU::op_cp_a_r; + opcode_table[0xbb] = &CPU::op_cp_a_r; + opcode_table[0xbc] = &CPU::op_cp_a_r; + opcode_table[0xbd] = &CPU::op_cp_a_r; + opcode_table[0xbe] = &CPU::op_cp_a_hl; + opcode_table[0xbf] = &CPU::op_cp_a_r; + opcode_table[0xc0] = &CPU::op_ret_f; + opcode_table[0xc1] = &CPU::op_pop_rr; + opcode_table[0xc2] = &CPU::op_jp_f_nn; + opcode_table[0xc3] = &CPU::op_jp_nn; + opcode_table[0xc4] = &CPU::op_call_f_nn; + opcode_table[0xc5] = &CPU::op_push_rr; + opcode_table[0xc6] = &CPU::op_add_a_n; + opcode_table[0xc7] = &CPU::op_rst_n<0x00>; + opcode_table[0xc8] = &CPU::op_ret_f; + opcode_table[0xc9] = &CPU::op_ret; + opcode_table[0xca] = &CPU::op_jp_f_nn; + opcode_table[0xcb] = &CPU::op_cb; + opcode_table[0xcc] = &CPU::op_call_f_nn; + opcode_table[0xcd] = &CPU::op_call_nn; + opcode_table[0xce] = &CPU::op_adc_a_n; + opcode_table[0xcf] = &CPU::op_rst_n<0x08>; + opcode_table[0xd0] = &CPU::op_ret_f; + opcode_table[0xd1] = &CPU::op_pop_rr; + opcode_table[0xd2] = &CPU::op_jp_f_nn; + opcode_table[0xd3] = &CPU::op_xx; + opcode_table[0xd4] = &CPU::op_call_f_nn; + opcode_table[0xd5] = &CPU::op_push_rr; + opcode_table[0xd6] = &CPU::op_sub_a_n; + opcode_table[0xd7] = &CPU::op_rst_n<0x10>; + opcode_table[0xd8] = &CPU::op_ret_f; + opcode_table[0xd9] = &CPU::op_reti; + opcode_table[0xda] = &CPU::op_jp_f_nn; + opcode_table[0xdb] = &CPU::op_xx; + opcode_table[0xdc] = &CPU::op_call_f_nn; + opcode_table[0xdd] = &CPU::op_xx; + opcode_table[0xde] = &CPU::op_sbc_a_n; + opcode_table[0xdf] = &CPU::op_rst_n<0x18>; + opcode_table[0xe0] = &CPU::op_ld_ffn_a; + opcode_table[0xe1] = &CPU::op_pop_rr; + opcode_table[0xe2] = &CPU::op_ld_ffc_a; + opcode_table[0xe3] = &CPU::op_xx; + opcode_table[0xe4] = &CPU::op_xx; + opcode_table[0xe5] = &CPU::op_push_rr; + opcode_table[0xe6] = &CPU::op_and_a_n; + opcode_table[0xe7] = &CPU::op_rst_n<0x20>; + opcode_table[0xe8] = &CPU::op_add_sp_n; + opcode_table[0xe9] = &CPU::op_jp_hl; + opcode_table[0xea] = &CPU::op_ld_nn_a; + opcode_table[0xeb] = &CPU::op_xx; + opcode_table[0xec] = &CPU::op_xx; + opcode_table[0xed] = &CPU::op_xx; + opcode_table[0xee] = &CPU::op_xor_a_n; + opcode_table[0xef] = &CPU::op_rst_n<0x28>; + opcode_table[0xf0] = &CPU::op_ld_a_ffn; + opcode_table[0xf1] = &CPU::op_pop_rr; + opcode_table[0xf2] = &CPU::op_ld_a_ffc; + opcode_table[0xf3] = &CPU::op_di; + opcode_table[0xf4] = &CPU::op_xx; + opcode_table[0xf5] = &CPU::op_push_rr; + opcode_table[0xf6] = &CPU::op_or_a_n; + opcode_table[0xf7] = &CPU::op_rst_n<0x30>; + opcode_table[0xf8] = &CPU::op_ld_hl_sp_n; + opcode_table[0xf9] = &CPU::op_ld_sp_hl; + opcode_table[0xfa] = &CPU::op_ld_a_nn; + opcode_table[0xfb] = &CPU::op_ei; + opcode_table[0xfc] = &CPU::op_xx; + opcode_table[0xfd] = &CPU::op_xx; + opcode_table[0xfe] = &CPU::op_cp_a_n; + opcode_table[0xff] = &CPU::op_rst_n<0x38>; + + opcode_table_cb[0x00] = &CPU::op_rlc_r; + opcode_table_cb[0x01] = &CPU::op_rlc_r; + opcode_table_cb[0x02] = &CPU::op_rlc_r; + opcode_table_cb[0x03] = &CPU::op_rlc_r; + opcode_table_cb[0x04] = &CPU::op_rlc_r; + opcode_table_cb[0x05] = &CPU::op_rlc_r; + opcode_table_cb[0x06] = &CPU::op_rlc_hl; + opcode_table_cb[0x07] = &CPU::op_rlc_r; + opcode_table_cb[0x08] = &CPU::op_rrc_r; + opcode_table_cb[0x09] = &CPU::op_rrc_r; + opcode_table_cb[0x0a] = &CPU::op_rrc_r; + opcode_table_cb[0x0b] = &CPU::op_rrc_r; + opcode_table_cb[0x0c] = &CPU::op_rrc_r; + opcode_table_cb[0x0d] = &CPU::op_rrc_r; + opcode_table_cb[0x0e] = &CPU::op_rrc_hl; + opcode_table_cb[0x0f] = &CPU::op_rrc_r; + opcode_table_cb[0x10] = &CPU::op_rl_r; + opcode_table_cb[0x11] = &CPU::op_rl_r; + opcode_table_cb[0x12] = &CPU::op_rl_r; + opcode_table_cb[0x13] = &CPU::op_rl_r; + opcode_table_cb[0x14] = &CPU::op_rl_r; + opcode_table_cb[0x15] = &CPU::op_rl_r; + opcode_table_cb[0x16] = &CPU::op_rl_hl; + opcode_table_cb[0x17] = &CPU::op_rl_r; + opcode_table_cb[0x18] = &CPU::op_rr_r; + opcode_table_cb[0x19] = &CPU::op_rr_r; + opcode_table_cb[0x1a] = &CPU::op_rr_r; + opcode_table_cb[0x1b] = &CPU::op_rr_r; + opcode_table_cb[0x1c] = &CPU::op_rr_r; + opcode_table_cb[0x1d] = &CPU::op_rr_r; + opcode_table_cb[0x1e] = &CPU::op_rr_hl; + opcode_table_cb[0x1f] = &CPU::op_rr_r; + opcode_table_cb[0x20] = &CPU::op_sla_r; + opcode_table_cb[0x21] = &CPU::op_sla_r; + opcode_table_cb[0x22] = &CPU::op_sla_r; + opcode_table_cb[0x23] = &CPU::op_sla_r; + opcode_table_cb[0x24] = &CPU::op_sla_r; + opcode_table_cb[0x25] = &CPU::op_sla_r; + opcode_table_cb[0x26] = &CPU::op_sla_hl; + opcode_table_cb[0x27] = &CPU::op_sla_r; + opcode_table_cb[0x28] = &CPU::op_sra_r; + opcode_table_cb[0x29] = &CPU::op_sra_r; + opcode_table_cb[0x2a] = &CPU::op_sra_r; + opcode_table_cb[0x2b] = &CPU::op_sra_r; + opcode_table_cb[0x2c] = &CPU::op_sra_r; + opcode_table_cb[0x2d] = &CPU::op_sra_r; + opcode_table_cb[0x2e] = &CPU::op_sra_hl; + opcode_table_cb[0x2f] = &CPU::op_sra_r; + opcode_table_cb[0x30] = &CPU::op_swap_r; + opcode_table_cb[0x31] = &CPU::op_swap_r; + opcode_table_cb[0x32] = &CPU::op_swap_r; + opcode_table_cb[0x33] = &CPU::op_swap_r; + opcode_table_cb[0x34] = &CPU::op_swap_r; + opcode_table_cb[0x35] = &CPU::op_swap_r; + opcode_table_cb[0x36] = &CPU::op_swap_hl; + opcode_table_cb[0x37] = &CPU::op_swap_r; + opcode_table_cb[0x38] = &CPU::op_srl_r; + opcode_table_cb[0x39] = &CPU::op_srl_r; + opcode_table_cb[0x3a] = &CPU::op_srl_r; + opcode_table_cb[0x3b] = &CPU::op_srl_r; + opcode_table_cb[0x3c] = &CPU::op_srl_r; + opcode_table_cb[0x3d] = &CPU::op_srl_r; + opcode_table_cb[0x3e] = &CPU::op_srl_hl; + opcode_table_cb[0x3f] = &CPU::op_srl_r; + opcode_table_cb[0x40] = &CPU::op_bit_n_r<0, B>; + opcode_table_cb[0x41] = &CPU::op_bit_n_r<0, C>; + opcode_table_cb[0x42] = &CPU::op_bit_n_r<0, D>; + opcode_table_cb[0x43] = &CPU::op_bit_n_r<0, E>; + opcode_table_cb[0x44] = &CPU::op_bit_n_r<0, H>; + opcode_table_cb[0x45] = &CPU::op_bit_n_r<0, L>; + opcode_table_cb[0x46] = &CPU::op_bit_n_hl<0>; + opcode_table_cb[0x47] = &CPU::op_bit_n_r<0, A>; + opcode_table_cb[0x48] = &CPU::op_bit_n_r<1, B>; + opcode_table_cb[0x49] = &CPU::op_bit_n_r<1, C>; + opcode_table_cb[0x4a] = &CPU::op_bit_n_r<1, D>; + opcode_table_cb[0x4b] = &CPU::op_bit_n_r<1, E>; + opcode_table_cb[0x4c] = &CPU::op_bit_n_r<1, H>; + opcode_table_cb[0x4d] = &CPU::op_bit_n_r<1, L>; + opcode_table_cb[0x4e] = &CPU::op_bit_n_hl<1>; + opcode_table_cb[0x4f] = &CPU::op_bit_n_r<1, A>; + opcode_table_cb[0x50] = &CPU::op_bit_n_r<2, B>; + opcode_table_cb[0x51] = &CPU::op_bit_n_r<2, C>; + opcode_table_cb[0x52] = &CPU::op_bit_n_r<2, D>; + opcode_table_cb[0x53] = &CPU::op_bit_n_r<2, E>; + opcode_table_cb[0x54] = &CPU::op_bit_n_r<2, H>; + opcode_table_cb[0x55] = &CPU::op_bit_n_r<2, L>; + opcode_table_cb[0x56] = &CPU::op_bit_n_hl<2>; + opcode_table_cb[0x57] = &CPU::op_bit_n_r<2, A>; + opcode_table_cb[0x58] = &CPU::op_bit_n_r<3, B>; + opcode_table_cb[0x59] = &CPU::op_bit_n_r<3, C>; + opcode_table_cb[0x5a] = &CPU::op_bit_n_r<3, D>; + opcode_table_cb[0x5b] = &CPU::op_bit_n_r<3, E>; + opcode_table_cb[0x5c] = &CPU::op_bit_n_r<3, H>; + opcode_table_cb[0x5d] = &CPU::op_bit_n_r<3, L>; + opcode_table_cb[0x5e] = &CPU::op_bit_n_hl<3>; + opcode_table_cb[0x5f] = &CPU::op_bit_n_r<3, A>; + opcode_table_cb[0x60] = &CPU::op_bit_n_r<4, B>; + opcode_table_cb[0x61] = &CPU::op_bit_n_r<4, C>; + opcode_table_cb[0x62] = &CPU::op_bit_n_r<4, D>; + opcode_table_cb[0x63] = &CPU::op_bit_n_r<4, E>; + opcode_table_cb[0x64] = &CPU::op_bit_n_r<4, H>; + opcode_table_cb[0x65] = &CPU::op_bit_n_r<4, L>; + opcode_table_cb[0x66] = &CPU::op_bit_n_hl<4>; + opcode_table_cb[0x67] = &CPU::op_bit_n_r<4, A>; + opcode_table_cb[0x68] = &CPU::op_bit_n_r<5, B>; + opcode_table_cb[0x69] = &CPU::op_bit_n_r<5, C>; + opcode_table_cb[0x6a] = &CPU::op_bit_n_r<5, D>; + opcode_table_cb[0x6b] = &CPU::op_bit_n_r<5, E>; + opcode_table_cb[0x6c] = &CPU::op_bit_n_r<5, H>; + opcode_table_cb[0x6d] = &CPU::op_bit_n_r<5, L>; + opcode_table_cb[0x6e] = &CPU::op_bit_n_hl<5>; + opcode_table_cb[0x6f] = &CPU::op_bit_n_r<5, A>; + opcode_table_cb[0x70] = &CPU::op_bit_n_r<6, B>; + opcode_table_cb[0x71] = &CPU::op_bit_n_r<6, C>; + opcode_table_cb[0x72] = &CPU::op_bit_n_r<6, D>; + opcode_table_cb[0x73] = &CPU::op_bit_n_r<6, E>; + opcode_table_cb[0x74] = &CPU::op_bit_n_r<6, H>; + opcode_table_cb[0x75] = &CPU::op_bit_n_r<6, L>; + opcode_table_cb[0x76] = &CPU::op_bit_n_hl<6>; + opcode_table_cb[0x77] = &CPU::op_bit_n_r<6, A>; + opcode_table_cb[0x78] = &CPU::op_bit_n_r<7, B>; + opcode_table_cb[0x79] = &CPU::op_bit_n_r<7, C>; + opcode_table_cb[0x7a] = &CPU::op_bit_n_r<7, D>; + opcode_table_cb[0x7b] = &CPU::op_bit_n_r<7, E>; + opcode_table_cb[0x7c] = &CPU::op_bit_n_r<7, H>; + opcode_table_cb[0x7d] = &CPU::op_bit_n_r<7, L>; + opcode_table_cb[0x7e] = &CPU::op_bit_n_hl<7>; + opcode_table_cb[0x7f] = &CPU::op_bit_n_r<7, A>; + opcode_table_cb[0x80] = &CPU::op_res_n_r<0, B>; + opcode_table_cb[0x81] = &CPU::op_res_n_r<0, C>; + opcode_table_cb[0x82] = &CPU::op_res_n_r<0, D>; + opcode_table_cb[0x83] = &CPU::op_res_n_r<0, E>; + opcode_table_cb[0x84] = &CPU::op_res_n_r<0, H>; + opcode_table_cb[0x85] = &CPU::op_res_n_r<0, L>; + opcode_table_cb[0x86] = &CPU::op_res_n_hl<0>; + opcode_table_cb[0x87] = &CPU::op_res_n_r<0, A>; + opcode_table_cb[0x88] = &CPU::op_res_n_r<1, B>; + opcode_table_cb[0x89] = &CPU::op_res_n_r<1, C>; + opcode_table_cb[0x8a] = &CPU::op_res_n_r<1, D>; + opcode_table_cb[0x8b] = &CPU::op_res_n_r<1, E>; + opcode_table_cb[0x8c] = &CPU::op_res_n_r<1, H>; + opcode_table_cb[0x8d] = &CPU::op_res_n_r<1, L>; + opcode_table_cb[0x8e] = &CPU::op_res_n_hl<1>; + opcode_table_cb[0x8f] = &CPU::op_res_n_r<1, A>; + opcode_table_cb[0x90] = &CPU::op_res_n_r<2, B>; + opcode_table_cb[0x91] = &CPU::op_res_n_r<2, C>; + opcode_table_cb[0x92] = &CPU::op_res_n_r<2, D>; + opcode_table_cb[0x93] = &CPU::op_res_n_r<2, E>; + opcode_table_cb[0x94] = &CPU::op_res_n_r<2, H>; + opcode_table_cb[0x95] = &CPU::op_res_n_r<2, L>; + opcode_table_cb[0x96] = &CPU::op_res_n_hl<2>; + opcode_table_cb[0x97] = &CPU::op_res_n_r<2, A>; + opcode_table_cb[0x98] = &CPU::op_res_n_r<3, B>; + opcode_table_cb[0x99] = &CPU::op_res_n_r<3, C>; + opcode_table_cb[0x9a] = &CPU::op_res_n_r<3, D>; + opcode_table_cb[0x9b] = &CPU::op_res_n_r<3, E>; + opcode_table_cb[0x9c] = &CPU::op_res_n_r<3, H>; + opcode_table_cb[0x9d] = &CPU::op_res_n_r<3, L>; + opcode_table_cb[0x9e] = &CPU::op_res_n_hl<3>; + opcode_table_cb[0x9f] = &CPU::op_res_n_r<3, A>; + opcode_table_cb[0xa0] = &CPU::op_res_n_r<4, B>; + opcode_table_cb[0xa1] = &CPU::op_res_n_r<4, C>; + opcode_table_cb[0xa2] = &CPU::op_res_n_r<4, D>; + opcode_table_cb[0xa3] = &CPU::op_res_n_r<4, E>; + opcode_table_cb[0xa4] = &CPU::op_res_n_r<4, H>; + opcode_table_cb[0xa5] = &CPU::op_res_n_r<4, L>; + opcode_table_cb[0xa6] = &CPU::op_res_n_hl<4>; + opcode_table_cb[0xa7] = &CPU::op_res_n_r<4, A>; + opcode_table_cb[0xa8] = &CPU::op_res_n_r<5, B>; + opcode_table_cb[0xa9] = &CPU::op_res_n_r<5, C>; + opcode_table_cb[0xaa] = &CPU::op_res_n_r<5, D>; + opcode_table_cb[0xab] = &CPU::op_res_n_r<5, E>; + opcode_table_cb[0xac] = &CPU::op_res_n_r<5, H>; + opcode_table_cb[0xad] = &CPU::op_res_n_r<5, L>; + opcode_table_cb[0xae] = &CPU::op_res_n_hl<5>; + opcode_table_cb[0xaf] = &CPU::op_res_n_r<5, A>; + opcode_table_cb[0xb0] = &CPU::op_res_n_r<6, B>; + opcode_table_cb[0xb1] = &CPU::op_res_n_r<6, C>; + opcode_table_cb[0xb2] = &CPU::op_res_n_r<6, D>; + opcode_table_cb[0xb3] = &CPU::op_res_n_r<6, E>; + opcode_table_cb[0xb4] = &CPU::op_res_n_r<6, H>; + opcode_table_cb[0xb5] = &CPU::op_res_n_r<6, L>; + opcode_table_cb[0xb6] = &CPU::op_res_n_hl<6>; + opcode_table_cb[0xb7] = &CPU::op_res_n_r<6, A>; + opcode_table_cb[0xb8] = &CPU::op_res_n_r<7, B>; + opcode_table_cb[0xb9] = &CPU::op_res_n_r<7, C>; + opcode_table_cb[0xba] = &CPU::op_res_n_r<7, D>; + opcode_table_cb[0xbb] = &CPU::op_res_n_r<7, E>; + opcode_table_cb[0xbc] = &CPU::op_res_n_r<7, H>; + opcode_table_cb[0xbd] = &CPU::op_res_n_r<7, L>; + opcode_table_cb[0xbe] = &CPU::op_res_n_hl<7>; + opcode_table_cb[0xbf] = &CPU::op_res_n_r<7, A>; + opcode_table_cb[0xc0] = &CPU::op_set_n_r<0, B>; + opcode_table_cb[0xc1] = &CPU::op_set_n_r<0, C>; + opcode_table_cb[0xc2] = &CPU::op_set_n_r<0, D>; + opcode_table_cb[0xc3] = &CPU::op_set_n_r<0, E>; + opcode_table_cb[0xc4] = &CPU::op_set_n_r<0, H>; + opcode_table_cb[0xc5] = &CPU::op_set_n_r<0, L>; + opcode_table_cb[0xc6] = &CPU::op_set_n_hl<0>; + opcode_table_cb[0xc7] = &CPU::op_set_n_r<0, A>; + opcode_table_cb[0xc8] = &CPU::op_set_n_r<1, B>; + opcode_table_cb[0xc9] = &CPU::op_set_n_r<1, C>; + opcode_table_cb[0xca] = &CPU::op_set_n_r<1, D>; + opcode_table_cb[0xcb] = &CPU::op_set_n_r<1, E>; + opcode_table_cb[0xcc] = &CPU::op_set_n_r<1, H>; + opcode_table_cb[0xcd] = &CPU::op_set_n_r<1, L>; + opcode_table_cb[0xce] = &CPU::op_set_n_hl<1>; + opcode_table_cb[0xcf] = &CPU::op_set_n_r<1, A>; + opcode_table_cb[0xd0] = &CPU::op_set_n_r<2, B>; + opcode_table_cb[0xd1] = &CPU::op_set_n_r<2, C>; + opcode_table_cb[0xd2] = &CPU::op_set_n_r<2, D>; + opcode_table_cb[0xd3] = &CPU::op_set_n_r<2, E>; + opcode_table_cb[0xd4] = &CPU::op_set_n_r<2, H>; + opcode_table_cb[0xd5] = &CPU::op_set_n_r<2, L>; + opcode_table_cb[0xd6] = &CPU::op_set_n_hl<2>; + opcode_table_cb[0xd7] = &CPU::op_set_n_r<2, A>; + opcode_table_cb[0xd8] = &CPU::op_set_n_r<3, B>; + opcode_table_cb[0xd9] = &CPU::op_set_n_r<3, C>; + opcode_table_cb[0xda] = &CPU::op_set_n_r<3, D>; + opcode_table_cb[0xdb] = &CPU::op_set_n_r<3, E>; + opcode_table_cb[0xdc] = &CPU::op_set_n_r<3, H>; + opcode_table_cb[0xdd] = &CPU::op_set_n_r<3, L>; + opcode_table_cb[0xde] = &CPU::op_set_n_hl<3>; + opcode_table_cb[0xdf] = &CPU::op_set_n_r<3, A>; + opcode_table_cb[0xe0] = &CPU::op_set_n_r<4, B>; + opcode_table_cb[0xe1] = &CPU::op_set_n_r<4, C>; + opcode_table_cb[0xe2] = &CPU::op_set_n_r<4, D>; + opcode_table_cb[0xe3] = &CPU::op_set_n_r<4, E>; + opcode_table_cb[0xe4] = &CPU::op_set_n_r<4, H>; + opcode_table_cb[0xe5] = &CPU::op_set_n_r<4, L>; + opcode_table_cb[0xe6] = &CPU::op_set_n_hl<4>; + opcode_table_cb[0xe7] = &CPU::op_set_n_r<4, A>; + opcode_table_cb[0xe8] = &CPU::op_set_n_r<5, B>; + opcode_table_cb[0xe9] = &CPU::op_set_n_r<5, C>; + opcode_table_cb[0xea] = &CPU::op_set_n_r<5, D>; + opcode_table_cb[0xeb] = &CPU::op_set_n_r<5, E>; + opcode_table_cb[0xec] = &CPU::op_set_n_r<5, H>; + opcode_table_cb[0xed] = &CPU::op_set_n_r<5, L>; + opcode_table_cb[0xee] = &CPU::op_set_n_hl<5>; + opcode_table_cb[0xef] = &CPU::op_set_n_r<5, A>; + opcode_table_cb[0xf0] = &CPU::op_set_n_r<6, B>; + opcode_table_cb[0xf1] = &CPU::op_set_n_r<6, C>; + opcode_table_cb[0xf2] = &CPU::op_set_n_r<6, D>; + opcode_table_cb[0xf3] = &CPU::op_set_n_r<6, E>; + opcode_table_cb[0xf4] = &CPU::op_set_n_r<6, H>; + opcode_table_cb[0xf5] = &CPU::op_set_n_r<6, L>; + opcode_table_cb[0xf6] = &CPU::op_set_n_hl<6>; + opcode_table_cb[0xf7] = &CPU::op_set_n_r<6, A>; + opcode_table_cb[0xf8] = &CPU::op_set_n_r<7, B>; + opcode_table_cb[0xf9] = &CPU::op_set_n_r<7, C>; + opcode_table_cb[0xfa] = &CPU::op_set_n_r<7, D>; + opcode_table_cb[0xfb] = &CPU::op_set_n_r<7, E>; + opcode_table_cb[0xfc] = &CPU::op_set_n_r<7, H>; + opcode_table_cb[0xfd] = &CPU::op_set_n_r<7, L>; + opcode_table_cb[0xfe] = &CPU::op_set_n_hl<7>; + opcode_table_cb[0xff] = &CPU::op_set_n_r<7, A>; +} + +#endif diff --git a/gameboy/cpu/cpu.cpp b/gameboy/cpu/cpu.cpp new file mode 100755 index 00000000..306e3aa1 --- /dev/null +++ b/gameboy/cpu/cpu.cpp @@ -0,0 +1,202 @@ +#include + +#define CPU_CPP +namespace GameBoy { + +#include "core/core.cpp" +#include "mmio/mmio.cpp" +#include "timing/timing.cpp" +#include "serialization.cpp" +CPU cpu; + +void CPU::Main() { + cpu.main(); +} + +void CPU::main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::CPU) { + scheduler.sync = Scheduler::SynchronizeMode::All; + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(trace) print(disassemble(r[PC]), "\n"); + interrupt_test(); + uint8 opcode = op_read(r[PC]++); + (this->*opcode_table[opcode])(); + } +} + +void CPU::interrupt_raise(CPU::Interrupt id) { + if(id == Interrupt::Vblank) { + status.interrupt_request_vblank = 1; + if(status.interrupt_enable_vblank) status.halt = false; + } + + if(id == Interrupt::Stat) { + status.interrupt_request_stat = 1; + if(status.interrupt_enable_stat) status.halt = false; + } + + if(id == Interrupt::Timer) { + status.interrupt_request_timer = 1; + if(status.interrupt_enable_timer) status.halt = false; + } + + if(id == Interrupt::Serial) { + status.interrupt_request_serial = 1; + if(status.interrupt_enable_serial) status.halt = false; + } + + if(id == Interrupt::Joypad) { + status.interrupt_request_joypad = 1; + if(status.interrupt_enable_joypad) status.halt = status.stop = false; + } +} + +void CPU::interrupt_test() { + if(status.ime) { + if(status.interrupt_request_vblank && status.interrupt_enable_vblank) { + status.interrupt_request_vblank = 0; + return interrupt_exec(0x0040); + } + + if(status.interrupt_request_stat && status.interrupt_enable_stat) { + status.interrupt_request_stat = 0; + return interrupt_exec(0x0048); + } + + if(status.interrupt_request_timer && status.interrupt_enable_timer) { + status.interrupt_request_timer = 0; + return interrupt_exec(0x0050); + } + + if(status.interrupt_request_serial && status.interrupt_enable_serial) { + status.interrupt_request_serial = 0; + return interrupt_exec(0x0058); + } + + if(status.interrupt_request_joypad && status.interrupt_enable_joypad) { + status.interrupt_request_joypad = 0; + return interrupt_exec(0x0060); + } + } +} + +void CPU::interrupt_exec(uint16 pc) { + status.ime = 0; + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = pc; + op_io(); + op_io(); + op_io(); +} + +void CPU::power() { + create(Main, 4 * 1024 * 1024); + + for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM + for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror) + for(unsigned n = 0xff80; n <= 0xfffe; n++) bus.mmio[n] = this; //HRAM + + bus.mmio[0xff00] = this; //JOYP + bus.mmio[0xff01] = this; //SB + bus.mmio[0xff02] = this; //SC + bus.mmio[0xff04] = this; //DIV + bus.mmio[0xff05] = this; //TIMA + bus.mmio[0xff06] = this; //TMA + bus.mmio[0xff07] = this; //TAC + bus.mmio[0xff0f] = this; //IF + bus.mmio[0xff46] = this; //DMA + bus.mmio[0xffff] = this; //IE + + if(system.cgb()) { + bus.mmio[0xff4d] = this; //KEY1 + bus.mmio[0xff51] = this; //HDMA1 + bus.mmio[0xff52] = this; //HDMA2 + bus.mmio[0xff53] = this; //HDMA3 + bus.mmio[0xff54] = this; //HDMA4 + bus.mmio[0xff55] = this; //HDMA5 + bus.mmio[0xff56] = this; //RP + bus.mmio[0xff6c] = this; //??? + bus.mmio[0xff70] = this; //SVBK + bus.mmio[0xff72] = this; //??? + bus.mmio[0xff73] = this; //??? + bus.mmio[0xff74] = this; //??? + bus.mmio[0xff75] = this; //??? + bus.mmio[0xff76] = this; //??? + bus.mmio[0xff77] = this; //??? + } + + for(auto &n : wram) n = 0x00; + for(auto &n : hram) n = 0x00; + + r[PC] = 0x0000; + r[SP] = 0x0000; + r[AF] = 0x0000; + r[BC] = 0x0000; + r[DE] = 0x0000; + r[HL] = 0x0000; + + status.clock = 0; + status.halt = false; + status.stop = false; + status.ei = false; + status.ime = 0; + + status.p15 = 0; + status.p14 = 0; + status.joyp = 0; + status.mlt_req = 0; + + status.serial_data = 0; + status.serial_bits = 0; + + status.serial_transfer = 0; + status.serial_clock = 0; + + status.div = 0; + + status.tima = 0; + + status.tma = 0; + + status.timer_enable = 0; + status.timer_clock = 0; + + status.interrupt_request_joypad = 0; + status.interrupt_request_serial = 0; + status.interrupt_request_timer = 0; + status.interrupt_request_stat = 0; + status.interrupt_request_vblank = 0; + + status.speed_double = 0; + status.speed_switch = 0; + + status.dma_source = 0; + status.dma_target = 0; + + status.dma_mode = 0; + status.dma_length = 0; + + status.ff6c = 0; + status.ff72 = 0; + status.ff73 = 0; + status.ff74 = 0; + status.ff75 = 0; + + status.wram_bank = 1; + + status.interrupt_enable_joypad = 0; + status.interrupt_enable_serial = 0; + status.interrupt_enable_timer = 0; + status.interrupt_enable_stat = 0; + status.interrupt_enable_vblank = 0; +} + +CPU::CPU() : trace(false) { + initialize_opcode_table(); +} + +} diff --git a/gameboy/cpu/cpu.hpp b/gameboy/cpu/cpu.hpp new file mode 100755 index 00000000..65e73acb --- /dev/null +++ b/gameboy/cpu/cpu.hpp @@ -0,0 +1,105 @@ +struct CPU : Processor, MMIO { + #include "core/core.hpp" + #include "mmio/mmio.hpp" + #include "timing/timing.hpp" + + bool trace; + + enum class Interrupt : unsigned { + Vblank, + Stat, + Timer, + Serial, + Joypad, + }; + + struct Status { + unsigned clock; + bool halt; + bool stop; + bool ei; + bool ime; + + //$ff00 JOYP + bool p15; + bool p14; + uint8 joyp; + uint8 mlt_req; + + //$ff01 SB + uint8 serial_data; + unsigned serial_bits; + + //$ff02 SC + bool serial_transfer; + bool serial_clock; + + //$ff04 DIV + uint8 div; + + //$ff05 TIMA + uint8 tima; + + //$ff06 TMA + uint8 tma; + + //$ff07 TAC + bool timer_enable; + unsigned timer_clock; + + //$ff0f IF + bool interrupt_request_joypad; + bool interrupt_request_serial; + bool interrupt_request_timer; + bool interrupt_request_stat; + bool interrupt_request_vblank; + + //$ff4d KEY1 + bool speed_double; + bool speed_switch; + + //$ff51,$ff52 HDMA1,HDMA2 + uint16 dma_source; + + //$ff53,$ff54 HDMA3,HDMA4 + uint16 dma_target; + + //$ff55 HDMA5 + bool dma_mode; + uint16 dma_length; + + //$ff6c ??? + uint8 ff6c; + + //$ff70 SVBK + uint3 wram_bank; + + //$ff72-$ff75 ??? + uint8 ff72; + uint8 ff73; + uint8 ff74; + uint8 ff75; + + //$ffff IE + bool interrupt_enable_joypad; + bool interrupt_enable_serial; + bool interrupt_enable_timer; + bool interrupt_enable_stat; + bool interrupt_enable_vblank; + } status; + + uint8 wram[32768]; //GB=8192, GBC=32768 + uint8 hram[128]; + + static void Main(); + void main(); + void interrupt_raise(Interrupt id); + void interrupt_test(); + void interrupt_exec(uint16 pc); + void power(); + + void serialize(serializer&); + CPU(); +}; + +extern CPU cpu; diff --git a/gameboy/cpu/mmio/mmio.cpp b/gameboy/cpu/mmio/mmio.cpp new file mode 100755 index 00000000..58fc4f03 --- /dev/null +++ b/gameboy/cpu/mmio/mmio.cpp @@ -0,0 +1,271 @@ +#ifdef CPU_CPP + +unsigned CPU::wram_addr(uint16 addr) const { + addr &= 0x1fff; + if(addr < 0x1000) return addr; + auto bank = status.wram_bank + (status.wram_bank == 0); + return (bank * 0x1000) + (addr & 0x0fff); +} + +void CPU::mmio_joyp_poll() { + unsigned button = 0, dpad = 0; + + button |= interface->inputPoll((unsigned)Input::Start) << 3; + button |= interface->inputPoll((unsigned)Input::Select) << 2; + button |= interface->inputPoll((unsigned)Input::B) << 1; + button |= interface->inputPoll((unsigned)Input::A) << 0; + + dpad |= interface->inputPoll((unsigned)Input::Down) << 3; + dpad |= interface->inputPoll((unsigned)Input::Up) << 2; + dpad |= interface->inputPoll((unsigned)Input::Left) << 1; + dpad |= interface->inputPoll((unsigned)Input::Right) << 0; + + status.joyp = 0x0f; + if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req; + if(status.p15 == 0) status.joyp &= button ^ 0x0f; + if(status.p14 == 0) status.joyp &= dpad ^ 0x0f; + if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad); +} + +uint8 CPU::mmio_read(uint16 addr) { + if(addr >= 0xc000 && addr <= 0xfdff) return wram[wram_addr(addr)]; + if(addr >= 0xff80 && addr <= 0xfffe) return hram[addr & 0x7f]; + + if(addr == 0xff00) { //JOYP + return (status.p15 << 5) + | (status.p14 << 4) + | (status.joyp << 0); + } + + if(addr == 0xff01) { //SB + return 0xff; + } + + if(addr == 0xff02) { //SC + return (status.serial_transfer << 7) + | (status.serial_clock << 0); + } + + if(addr == 0xff04) { //DIV + return status.div; + } + + if(addr == 0xff05) { //TIMA + return status.tima; + } + + if(addr == 0xff06) { //TMA + return status.tma; + } + + if(addr == 0xff07) { //TAC + return (status.timer_enable << 2) + | (status.timer_clock << 0); + } + + if(addr == 0xff0f) { //IF + return (status.interrupt_request_joypad << 4) + | (status.interrupt_request_serial << 3) + | (status.interrupt_request_timer << 2) + | (status.interrupt_request_stat << 1) + | (status.interrupt_request_vblank << 0); + } + + if(addr == 0xff4d) { //KEY1 + return (status.speed_double << 7); + } + + if(addr == 0xff55) { //HDMA5 + return (status.dma_length / 16) - 1; + } + + if(addr == 0xff56) { //RP + return 0x02; + } + + if(addr == 0xff6c) { //??? + return 0xfe | status.ff6c; + } + + if(addr == 0xff70) { //SVBK + return status.wram_bank; + } + + if(addr == 0xff72) { //??? + return status.ff72; + } + + if(addr == 0xff73) { //??? + return status.ff73; + } + + if(addr == 0xff74) { //??? + return status.ff74; + } + + if(addr == 0xff75) { //??? + return 0x8f | status.ff75; + } + + if(addr == 0xff76) { //??? + return 0x00; + } + + if(addr == 0xff77) { //??? + return 0x00; + } + + if(addr == 0xffff) { //IE + return (status.interrupt_enable_joypad << 4) + | (status.interrupt_enable_serial << 3) + | (status.interrupt_enable_timer << 2) + | (status.interrupt_enable_stat << 1) + | (status.interrupt_enable_vblank << 0); + } + + return 0x00; +} + +void CPU::mmio_write(uint16 addr, uint8 data) { + if(addr >= 0xc000 && addr <= 0xfdff) { wram[wram_addr(addr)] = data; return; } + if(addr >= 0xff80 && addr <= 0xfffe) { hram[addr & 0x7f] = data; return; } + + if(addr == 0xff00) { //JOYP + status.p15 = data & 0x20; + status.p14 = data & 0x10; + interface->joypWrite(status.p15, status.p14); + mmio_joyp_poll(); + return; + } + + if(addr == 0xff01) { //SB + status.serial_data = data; + return; + } + + if(addr == 0xff02) { //SC + status.serial_transfer = data & 0x80; + status.serial_clock = data & 0x01; + if(status.serial_transfer) status.serial_bits = 8; + return; + } + + if(addr == 0xff04) { //DIV + status.div = 0; + return; + } + + if(addr == 0xff05) { //TIMA + status.tima = data; + return; + } + + if(addr == 0xff06) { //TMA + status.tma = data; + return; + } + + if(addr == 0xff07) { //TAC + status.timer_enable = data & 0x04; + status.timer_clock = data & 0x03; + return; + } + + if(addr == 0xff0f) { //IF + status.interrupt_request_joypad = data & 0x10; + status.interrupt_request_serial = data & 0x08; + status.interrupt_request_timer = data & 0x04; + status.interrupt_request_stat = data & 0x02; + status.interrupt_request_vblank = data & 0x01; + return; + } + + if(addr == 0xff46) { //DMA + for(unsigned n = 0x00; n <= 0x9f; n++) { + bus.write(0xfe00 + n, bus.read((data << 8) + n)); + add_clocks(4); + } + return; + } + + if(addr == 0xff4d) { //KEY1 + status.speed_switch = data & 0x01; + return; + } + + if(addr == 0xff51) { //HDMA1 + status.dma_source = (status.dma_source & 0x00ff) | (data << 8); + return; + } + + if(addr == 0xff52) { //HDMA2 + status.dma_source = (status.dma_source & 0xff00) | (data << 0); + return; + } + + if(addr == 0xff53) { //HDMA3 + status.dma_target = (status.dma_target & 0x00ff) | (data << 8); + return; + } + + if(addr == 0xff54) { //HDMA4 + status.dma_target = (status.dma_target & 0xff00) | (data << 0); + return; + } + + if(addr == 0xff55) { //HDMA5 + status.dma_mode = data & 0x80; + status.dma_length = ((data & 0x7f) + 1) * 16; + + if(status.dma_mode == 0) do { + bus.write(status.dma_target++, bus.read(status.dma_source++)); + add_clocks(4 << status.speed_double); + } while(--status.dma_length); + return; + } + + if(addr == 0xff56) { //RP + return; + } + + if(addr == 0xff6c) { //??? + status.ff6c = data & 0x01; + return; + } + + if(addr == 0xff72) { //??? + status.ff72 = data; + return; + } + + if(addr == 0xff73) { //??? + status.ff73 = data; + return; + } + + if(addr == 0xff74) { //??? + status.ff74 = data; + return; + } + + if(addr == 0xff75) { //??? + status.ff75 = data & 0x70; + return; + } + + if(addr == 0xff70) { //SVBK + status.wram_bank = data & 0x07; + return; + } + + if(addr == 0xffff) { //IE + status.interrupt_enable_joypad = data & 0x10; + status.interrupt_enable_serial = data & 0x08; + status.interrupt_enable_timer = data & 0x04; + status.interrupt_enable_stat = data & 0x02; + status.interrupt_enable_vblank = data & 0x01; + return; + } +} + +#endif diff --git a/gameboy/cpu/mmio/mmio.hpp b/gameboy/cpu/mmio/mmio.hpp new file mode 100755 index 00000000..14408995 --- /dev/null +++ b/gameboy/cpu/mmio/mmio.hpp @@ -0,0 +1,4 @@ +unsigned wram_addr(uint16 addr) const; +void mmio_joyp_poll(); +uint8 mmio_read(uint16 addr); +void mmio_write(uint16 addr, uint8 data); diff --git a/gameboy/cpu/serialization.cpp b/gameboy/cpu/serialization.cpp new file mode 100755 index 00000000..5a2b8d5c --- /dev/null +++ b/gameboy/cpu/serialization.cpp @@ -0,0 +1,76 @@ +#ifdef CPU_CPP + +void CPU::serialize(serializer &s) { + Processor::serialize(s); + + s.array(wram); + s.array(hram); + + s.integer(r.a.data); + s.integer(r.f.z); + s.integer(r.f.n); + s.integer(r.f.h); + s.integer(r.f.c); + s.integer(r.b.data); + s.integer(r.c.data); + s.integer(r.d.data); + s.integer(r.e.data); + s.integer(r.h.data); + s.integer(r.l.data); + s.integer(r.sp.data); + s.integer(r.pc.data); + + s.integer(status.clock); + s.integer(status.halt); + s.integer(status.stop); + s.integer(status.ei); + s.integer(status.ime); + + s.integer(status.p15); + s.integer(status.p14); + s.integer(status.joyp); + s.integer(status.mlt_req); + + s.integer(status.serial_data); + s.integer(status.serial_bits); + + s.integer(status.serial_transfer); + s.integer(status.serial_clock); + + s.integer(status.div); + s.integer(status.tima); + s.integer(status.tma); + s.integer(status.timer_enable); + s.integer(status.timer_clock); + + s.integer(status.interrupt_request_joypad); + s.integer(status.interrupt_request_serial); + s.integer(status.interrupt_request_timer); + s.integer(status.interrupt_request_stat); + s.integer(status.interrupt_request_vblank); + + s.integer(status.speed_double); + s.integer(status.speed_switch); + + s.integer(status.dma_source); + s.integer(status.dma_target); + s.integer(status.dma_mode); + s.integer(status.dma_length); + + s.integer(status.ff6c); + + s.integer(status.wram_bank); + + s.integer(status.ff72); + s.integer(status.ff73); + s.integer(status.ff74); + s.integer(status.ff75); + + s.integer(status.interrupt_enable_joypad); + s.integer(status.interrupt_enable_serial); + s.integer(status.interrupt_enable_timer); + s.integer(status.interrupt_enable_stat); + s.integer(status.interrupt_enable_vblank); +} + +#endif diff --git a/gameboy/cpu/timing/opcode.cpp b/gameboy/cpu/timing/opcode.cpp new file mode 100755 index 00000000..5774670b --- /dev/null +++ b/gameboy/cpu/timing/opcode.cpp @@ -0,0 +1,28 @@ +#ifdef CPU_CPP + +void CPU::op_io() { + cycle_edge(); + add_clocks(4); +} + +uint8 CPU::op_read(uint16 addr) { + cycle_edge(); + uint8 r = bus.read(addr); + add_clocks(4); + return r; +} + +void CPU::op_write(uint16 addr, uint8 data) { + cycle_edge(); + bus.write(addr, data); + add_clocks(4); +} + +void CPU::cycle_edge() { + if(status.ei) { + status.ei = false; + status.ime = 1; + } +} + +#endif diff --git a/gameboy/cpu/timing/timing.cpp b/gameboy/cpu/timing/timing.cpp new file mode 100755 index 00000000..cc5e3abd --- /dev/null +++ b/gameboy/cpu/timing/timing.cpp @@ -0,0 +1,90 @@ +//70224 clocks/frame +// 456 clocks/scanline +// 154 scanlines/frame + +#ifdef CPU_CPP + +#include "opcode.cpp" + +void CPU::add_clocks(unsigned clocks) { + system.clocks_executed += clocks; + if(system.sgb()) scheduler.exit(Scheduler::ExitReason::StepEvent); + + status.clock += clocks; + if(status.clock >= 4 * 1024 * 1024) { + status.clock -= 4 * 1024 * 1024; + cartridge.mbc3.second(); + } + + //4MHz / N(hz) - 1 = mask + if((status.clock & 15) == 0) timer_262144hz(); + if((status.clock & 63) == 0) timer_65536hz(); + if((status.clock & 255) == 0) timer_16384hz(); + if((status.clock & 511) == 0) timer_8192hz(); + if((status.clock & 1023) == 0) timer_4096hz(); + + lcd.clock -= clocks * lcd.frequency; + if(lcd.clock <= 0) co_switch(scheduler.active_thread = lcd.thread); + + apu.clock -= clocks * apu.frequency; + if(apu.clock <= 0) co_switch(scheduler.active_thread = apu.thread); +} + +void CPU::timer_262144hz() { + if(status.timer_enable && status.timer_clock == 1) { + if(++status.tima == 0) { + status.tima = status.tma; + interrupt_raise(Interrupt::Timer); + } + } +} + +void CPU::timer_65536hz() { + if(status.timer_enable && status.timer_clock == 2) { + if(++status.tima == 0) { + status.tima = status.tma; + interrupt_raise(Interrupt::Timer); + } + } +} + +void CPU::timer_16384hz() { + if(status.timer_enable && status.timer_clock == 3) { + if(++status.tima == 0) { + status.tima = status.tma; + interrupt_raise(Interrupt::Timer); + } + } + + status.div++; +} + +void CPU::timer_8192hz() { + if(status.serial_transfer && status.serial_clock) { + if(--status.serial_bits == 0) { + status.serial_transfer = 0; + interrupt_raise(Interrupt::Serial); + } + } +} + +void CPU::timer_4096hz() { + if(status.timer_enable && status.timer_clock == 0) { + if(++status.tima == 0) { + status.tima = status.tma; + interrupt_raise(Interrupt::Timer); + } + } +} + +void CPU::hblank() { + if(status.dma_mode == 1 && status.dma_length) { + for(unsigned n = 0; n < 16; n++) { + bus.write(status.dma_target++, bus.read(status.dma_source++)); + add_clocks(4); + } + status.dma_length -= 16; + } +} + +#endif diff --git a/gameboy/cpu/timing/timing.hpp b/gameboy/cpu/timing/timing.hpp new file mode 100755 index 00000000..6c16c47e --- /dev/null +++ b/gameboy/cpu/timing/timing.hpp @@ -0,0 +1,13 @@ +void add_clocks(unsigned clocks); +void timer_262144hz(); +void timer_65536hz(); +void timer_16384hz(); +void timer_8192hz(); +void timer_4096hz(); +void hblank(); + +//opcode.cpp +void op_io(); +uint8 op_read(uint16 addr); +void op_write(uint16 addr, uint8 data); +void cycle_edge(); diff --git a/gameboy/gameboy.hpp b/gameboy/gameboy.hpp new file mode 100755 index 00000000..01893319 --- /dev/null +++ b/gameboy/gameboy.hpp @@ -0,0 +1,114 @@ +#ifndef GAMEBOY_HPP +#define GAMEBOY_HPP + +namespace GameBoy { + namespace Info { + static const char Name[] = "bgameboy"; + static const unsigned SerializerVersion = 3; + } +} + +/* + bgameboy - Game Boy, Super Game Boy, and Game Boy Color emulator + author: byuu + license: GPLv3 + project started: 2010-12-27 +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +using namespace nall; + +namespace GameBoy { + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + + typedef uint_t< 1> uint1; + typedef uint_t< 2> uint2; + typedef uint_t< 3> uint3; + typedef uint_t< 4> uint4; + typedef uint_t< 5> uint5; + typedef uint_t< 6> uint6; + typedef uint_t< 7> uint7; + + typedef uint_t< 9> uint9; + typedef uint_t<10> uint10; + typedef uint_t<11> uint11; + typedef uint_t<12> uint12; + typedef uint_t<13> uint13; + typedef uint_t<14> uint14; + typedef uint_t<15> uint15; + + typedef uint_t<17> uint17; + typedef uint_t<18> uint18; + typedef uint_t<19> uint19; + typedef uint_t<20> uint20; + typedef uint_t<21> uint21; + typedef uint_t<22> uint22; + typedef uint_t<23> uint23; + typedef uint_t<24> uint24; + typedef uint_t<25> uint25; + typedef uint_t<26> uint26; + typedef uint_t<27> uint27; + typedef uint_t<28> uint28; + typedef uint_t<29> uint29; + typedef uint_t<30> uint30; + typedef uint_t<31> uint31; + + template + alwaysinline bool within(uint16 addr) { + static const uint16 mask = ~(hi ^ lo); + return (addr & mask) == lo; + } + + struct Processor { + cothread_t thread; + unsigned frequency; + int64 clock; + + inline void create(void (*entrypoint)(), unsigned frequency) { + if(thread) co_delete(thread); + thread = co_create(65536 * sizeof(void*), entrypoint); + this->frequency = frequency; + clock = 0; + } + + inline void serialize(serializer &s) { + s.integer(frequency); + s.integer(clock); + } + + inline Processor() : thread(nullptr) { + } + + inline ~Processor() { + if(thread) co_delete(thread); + } + }; + + #include + #include + #include + #include + #include + #include + #include + #include + #include +}; + +#endif diff --git a/gameboy/interface/interface.cpp b/gameboy/interface/interface.cpp new file mode 100755 index 00000000..0a6d5f2a --- /dev/null +++ b/gameboy/interface/interface.cpp @@ -0,0 +1,27 @@ +#include + +namespace GameBoy { + +Interface *interface = nullptr; + +void Interface::lcdScanline() { +} + +void Interface::joypWrite(bool p15, bool p14) { +} + +void Interface::videoRefresh(const uint16_t *data) { +} + +void Interface::audioSample(int16_t center, int16_t left, int16_t right) { +} + +bool Interface::inputPoll(unsigned id) { + return false; +} + +void Interface::message(const string &text) { + print(text, "\n"); +} + +} diff --git a/gameboy/interface/interface.hpp b/gameboy/interface/interface.hpp new file mode 100755 index 00000000..918e606b --- /dev/null +++ b/gameboy/interface/interface.hpp @@ -0,0 +1,12 @@ +struct Interface { + virtual void lcdScanline(); + virtual void joypWrite(bool p15, bool p14); + + virtual void videoRefresh(const uint16_t *data); + virtual void audioSample(int16_t center, int16_t left, int16_t right); + virtual bool inputPoll(unsigned id); + + virtual void message(const string &text); +}; + +extern Interface *interface; diff --git a/gameboy/lcd/cgb.cpp b/gameboy/lcd/cgb.cpp new file mode 100755 index 00000000..c29230b3 --- /dev/null +++ b/gameboy/lcd/cgb.cpp @@ -0,0 +1,185 @@ +#ifdef LCD_CPP + +void LCD::cgb_render() { + for(unsigned n = 0; n < 160; n++) { + line[n] = 0x7fff; + origin[n] = Origin::None; + } + + if(status.display_enable) { + cgb_render_bg(); + if(status.window_display_enable) cgb_render_window(); + if(status.ob_enable) cgb_render_ob(); + } + + uint16 *output = screen + status.ly * 160; + for(unsigned n = 0; n < 160; n++) output[n] = line[n]; + interface->lcdScanline(); +} + +//Attributes: +//0x80: 0 = OAM priority, 1 = BG priority +//0x40: vertical flip +//0x20: horizontal flip +//0x08: VRAM bank# +//0x07: palette# +void LCD::cgb_read_tile(bool select, unsigned x, unsigned y, unsigned &tile, unsigned &attr, unsigned &data) { + unsigned tmaddr = 0x1800 + (select << 10); + tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff; + + tile = vram[0x0000 + tmaddr]; + attr = vram[0x2000 + tmaddr]; + + unsigned tdaddr = attr & 0x08 ? 0x2000 : 0x0000; + if(status.bg_tiledata_select == 0) { + tdaddr += 0x1000 + ((int8)tile << 4); + } else { + tdaddr += 0x0000 + (tile << 4); + } + + y &= 7; + if(attr & 0x40) y ^= 7; + tdaddr += y << 1; + + data = vram[tdaddr++] << 0; + data |= vram[tdaddr++] << 8; + if(attr & 0x20) data = hflip(data); +} + +void LCD::cgb_render_bg() { + unsigned iy = (status.ly + status.scy) & 255; + unsigned ix = status.scx, tx = ix & 7; + + unsigned tile, attr, data; + cgb_read_tile(status.bg_tilemap_select, ix, iy, tile, attr, data); + + for(unsigned ox = 0; ox < 160; ox++) { + unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); + unsigned palette_index = ((attr & 0x07) << 3) + (index << 1); + unsigned palette = 0; + palette |= bgpd[palette_index++] << 0; + palette |= bgpd[palette_index++] << 8; + palette &= 0x7fff; + + line[ox] = palette; + origin[ox] = (attr & 0x80 ? Origin::BGP : Origin::BG); + + ix = (ix + 1) & 255; + tx = (tx + 1) & 7; + if(tx == 0) cgb_read_tile(status.bg_tilemap_select, ix, iy, tile, attr, data); + } +} + +void LCD::cgb_render_window() { + if(status.ly - status.wy >= 144u) return; + if(status.wx >= 167u) return; + unsigned iy = status.wyc++; + unsigned ix = (7 - status.wx) & 255, tx = ix & 7; + + unsigned tile, attr, data; + cgb_read_tile(status.window_tilemap_select, ix, iy, tile, attr, data); + + for(unsigned ox = 0; ox < 160; ox++) { + unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); + unsigned palette_index = ((attr & 0x07) << 3) + (index << 1); + unsigned palette = 0; + palette |= bgpd[palette_index++] << 0; + palette |= bgpd[palette_index++] << 8; + palette &= 0x7fff; + + if(ox - (status.wx - 7) < 160u) { + line[ox] = palette; + origin[ox] = (attr & 0x80 ? Origin::BGP : Origin::BG); + } + + ix = (ix + 1) & 255; + tx = (tx + 1) & 7; + if(tx == 0) cgb_read_tile(status.window_tilemap_select, ix, iy, tile, attr, data); + } +} + +//Attributes: +//0x80: 0 = OBJ above BG, 1 = BG above OBJ +//0x40: vertical flip +//0x20: horizontal flip +//0x08: VRAM bank# +//0x07: palette# +void LCD::cgb_render_ob() { + const unsigned Height = (status.ob_size == 0 ? 8 : 16); + unsigned sprite[10], sprites = 0; + + //find first ten sprites on this scanline + for(unsigned s = 0; s < 40; s++) { + unsigned sy = oam[(s << 2) + 0] - 16; + unsigned sx = oam[(s << 2) + 1] - 8; + + sy = status.ly - sy; + if(sy >= Height) continue; + + sprite[sprites++] = s; + if(sprites == 10) break; + } + + //sort by X-coordinate, when equal, lower address comes first + for(unsigned x = 0; x < sprites; x++) { + for(unsigned y = x + 1; y < sprites; y++) { + signed sx = oam[(sprite[x] << 2) + 1] - 8; + signed sy = oam[(sprite[y] << 2) + 1] - 8; + if(sy < sx) { + sprite[x] ^= sprite[y]; + sprite[y] ^= sprite[x]; + sprite[x] ^= sprite[y]; + } + } + } + + //render backwards, so that first sprite has highest priority + for(signed s = sprites - 1; s >= 0; s--) { + unsigned n = sprite[s] << 2; + unsigned sy = oam[n + 0] - 16; + unsigned sx = oam[n + 1] - 8; + unsigned tile = oam[n + 2]; + unsigned attr = oam[n + 3]; + + sy = status.ly - sy; + if(sy >= Height) continue; + if(attr & 0x40) sy ^= (Height - 1); + + unsigned tdaddr = (attr & 0x08 ? 0x2000 : 0x0000) + (tile << 4) + (sy << 1), data = 0; + data |= vram[tdaddr++] << 0; + data |= vram[tdaddr++] << 8; + if(attr & 0x20) data = hflip(data); + + for(unsigned tx = 0; tx < 8; tx++) { + unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); + if(index == 0) continue; + + unsigned palette_index = ((attr & 0x07) << 3) + (index << 1); + unsigned palette = 0; + palette |= obpd[palette_index++] << 0; + palette |= obpd[palette_index++] << 8; + palette &= 0x7fff; + + unsigned ox = sx + tx; + + if(ox < 160) { + //When LCDC.D0 (BG enable) is off, OB is always rendered above BG+Window + if(status.bg_enable) { + if(origin[ox] == Origin::BGP) continue; + if(attr & 0x80) { + if(origin[ox] == Origin::BG || origin[ox] == Origin::BGP) { + if(line[ox] > 0) continue; + } + } + } + line[ox] = palette; + origin[ox] = Origin::OB; + } + } + } +} + +#endif diff --git a/gameboy/lcd/dmg.cpp b/gameboy/lcd/dmg.cpp new file mode 100755 index 00000000..d8e6d98e --- /dev/null +++ b/gameboy/lcd/dmg.cpp @@ -0,0 +1,145 @@ +#ifdef LCD_CPP + +void LCD::dmg_render() { + for(unsigned n = 0; n < 160; n++) { + line[n] = 0x00; + origin[n] = Origin::None; + } + + if(status.display_enable) { + if(status.bg_enable) dmg_render_bg(); + if(status.window_display_enable) dmg_render_window(); + if(status.ob_enable) dmg_render_ob(); + } + + uint16 *output = screen + status.ly * 160; + for(unsigned n = 0; n < 160; n++) output[n] = line[n]; + interface->lcdScanline(); +} + +uint16 LCD::dmg_read_tile(bool select, unsigned x, unsigned y) { + unsigned tmaddr = 0x1800 + (select << 10), tdaddr; + tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff; + if(status.bg_tiledata_select == 0) { + tdaddr = 0x1000 + ((int8)vram[tmaddr] << 4); + } else { + tdaddr = 0x0000 + (vram[tmaddr] << 4); + } + tdaddr += (y & 7) << 1; + return (vram[tdaddr + 0] << 0) | (vram[tdaddr + 1] << 8); +} + +void LCD::dmg_render_bg() { + unsigned iy = (status.ly + status.scy) & 255; + unsigned ix = status.scx, tx = ix & 7; + unsigned data = dmg_read_tile(status.bg_tilemap_select, ix, iy); + + for(unsigned ox = 0; ox < 160; ox++) { + uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); + + line[ox] = bgp[palette]; + origin[ox] = Origin::BG; + + ix = (ix + 1) & 255; + tx = (tx + 1) & 7; + + if(tx == 0) data = dmg_read_tile(status.bg_tilemap_select, ix, iy); + } +} + +void LCD::dmg_render_window() { + if(status.ly - status.wy >= 144u) return; + if(status.wx >= 167u) return; + unsigned iy = status.wyc++; + unsigned ix = (7 - status.wx) & 255, tx = ix & 7; + unsigned data = dmg_read_tile(status.window_tilemap_select, ix, iy); + + for(unsigned ox = 0; ox < 160; ox++) { + uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); + if(ox - (status.wx - 7) < 160u) { + line[ox] = bgp[palette]; + origin[ox] = Origin::BG; + } + + ix = (ix + 1) & 255; + tx = (tx + 1) & 7; + + if(tx == 0) data = dmg_read_tile(status.window_tilemap_select, ix, iy); + } +} + +//Attributes: +//0x80: 0 = OBJ above BG, 1 = BG above OBJ +//0x40: vertical flip +//0x20: horizontal flip +//0x10: palette# +void LCD::dmg_render_ob() { + const unsigned Height = (status.ob_size == 0 ? 8 : 16); + unsigned sprite[10], sprites = 0; + + //find first ten sprites on this scanline + for(unsigned s = 0; s < 40; s++) { + unsigned sy = oam[(s << 2) + 0] - 16; + unsigned sx = oam[(s << 2) + 1] - 8; + + sy = status.ly - sy; + if(sy >= Height) continue; + + sprite[sprites++] = s; + if(sprites == 10) break; + } + + //sort by X-coordinate, when equal, lower address comes first + for(unsigned x = 0; x < sprites; x++) { + for(unsigned y = x + 1; y < sprites; y++) { + signed sx = oam[(sprite[x] << 2) + 1] - 8; + signed sy = oam[(sprite[y] << 2) + 1] - 8; + if(sy < sx) { + sprite[x] ^= sprite[y]; + sprite[y] ^= sprite[x]; + sprite[x] ^= sprite[y]; + } + } + } + + //render backwards, so that first sprite has highest priority + for(signed s = sprites - 1; s >= 0; s--) { + unsigned n = sprite[s] << 2; + unsigned sy = oam[n + 0] - 16; + unsigned sx = oam[n + 1] - 8; + unsigned tile = oam[n + 2]; + unsigned attr = oam[n + 3]; + + sy = status.ly - sy; + if(sy >= Height) continue; + if(attr & 0x40) sy ^= (Height - 1); + + unsigned tdaddr = (tile << 4) + (sy << 1), data = 0; + data |= vram[tdaddr++] << 0; + data |= vram[tdaddr++] << 8; + if(attr & 0x20) data = hflip(data); + + for(unsigned tx = 0; tx < 8; tx++) { + uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); + if(palette == 0) continue; + + palette = obp[(bool)(attr & 0x10)][palette]; + unsigned ox = sx + tx; + + if(ox < 160) { + if(attr & 0x80) { + if(origin[ox] == Origin::BG) { + if(line[ox] > 0) continue; + } + } + line[ox] = palette; + origin[ox] = Origin::OB; + } + } + } +} + +#endif diff --git a/gameboy/lcd/lcd.cpp b/gameboy/lcd/lcd.cpp new file mode 100755 index 00000000..7a3607c6 --- /dev/null +++ b/gameboy/lcd/lcd.cpp @@ -0,0 +1,158 @@ +#include + +//LY = 0-153 +//Raster = 0-143 +//Vblank = 144-153 + +//LX = 0-455 + +#define LCD_CPP +namespace GameBoy { + +#include "dmg.cpp" +#include "cgb.cpp" +#include "mmio/mmio.cpp" +#include "serialization.cpp" +LCD lcd; + +void LCD::Main() { + lcd.main(); +} + +void LCD::main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + add_clocks(4); + status.lx += 4; + if(status.lx >= 456) scanline(); + + if(status.display_enable && status.lx == 0) { + if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat); + } + + if(status.display_enable && status.lx == 252) { + if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat); + cpu.hblank(); + } + } +} + +void LCD::add_clocks(unsigned clocks) { + clock += clocks * cpu.frequency; + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) { + co_switch(scheduler.active_thread = cpu.thread); + } +} + +void LCD::scanline() { + status.lx -= 456; + if(++status.ly == 154) frame(); + + if(status.display_enable && status.interrupt_lyc == true) { + if(status.ly == status.lyc) cpu.interrupt_raise(CPU::Interrupt::Stat); + } + + if(status.ly < 144) { + system.cgb() == false ? dmg_render() : cgb_render(); + } + + if(status.display_enable && status.ly == 144) { + cpu.interrupt_raise(CPU::Interrupt::Vblank); + if(status.interrupt_vblank) cpu.interrupt_raise(CPU::Interrupt::Stat); + } +} + +void LCD::frame() { + interface->videoRefresh(screen); + cpu.mmio_joyp_poll(); + + status.ly = 0; + status.wyc = 0; + scheduler.exit(Scheduler::ExitReason::FrameEvent); +} + +unsigned LCD::hflip(unsigned data) const { + return ((data & 0x8080) >> 7) | ((data & 0x4040) >> 5) + | ((data & 0x2020) >> 3) | ((data & 0x1010) >> 1) + | ((data & 0x0808) << 1) | ((data & 0x0404) << 3) + | ((data & 0x0202) << 5) | ((data & 0x0101) << 7); +} + +void LCD::power() { + create(Main, 4 * 1024 * 1024); + + for(unsigned n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM + for(unsigned n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM + + bus.mmio[0xff40] = this; //LCDC + bus.mmio[0xff41] = this; //STAT + bus.mmio[0xff42] = this; //SCY + bus.mmio[0xff43] = this; //SCX + bus.mmio[0xff44] = this; //LY + bus.mmio[0xff45] = this; //LYC + bus.mmio[0xff47] = this; //BGP + bus.mmio[0xff48] = this; //OBP0 + bus.mmio[0xff49] = this; //OBP1 + bus.mmio[0xff4a] = this; //WY + bus.mmio[0xff4b] = this; //WX + + if(system.cgb()) { + bus.mmio[0xff4f] = this; //VBK + bus.mmio[0xff68] = this; //BGPI + bus.mmio[0xff69] = this; //BGPD + bus.mmio[0xff6a] = this; //OBPI + bus.mmio[0xff6b] = this; //OBPD + } + + for(auto &n : screen) n = 0x0000; + for(auto &n : line) n = 0x0000; + for(auto &n : origin) n = Origin::None; + + for(auto &n : vram) n = 0x00; + for(auto &n : oam) n = 0x00; + for(auto &n : bgp) n = 0x00; + for(auto &n : obp[0]) n = 0x00; + for(auto &n : obp[1]) n = 0x00; + for(auto &n : bgpd) n = 0x0000; + for(auto &n : obpd) n = 0x0000; + + status.lx = 0; + status.wyc = 0; + + status.display_enable = 0; + status.window_tilemap_select = 0; + status.window_display_enable = 0; + status.bg_tiledata_select = 0; + status.bg_tilemap_select = 0; + status.ob_size = 0; + status.ob_enable = 0; + status.bg_enable = 0; + + status.interrupt_lyc = 0; + status.interrupt_oam = 0; + status.interrupt_vblank = 0; + status.interrupt_hblank = 0; + + status.scy = 0; + status.scx = 0; + status.ly = 0; + status.lyc = 0; + status.wy = 0; + status.wx = 0; + + status.vram_bank = 0; + + status.bgpi_increment = 0; + status.bgpi = 0; + + status.obpi_increment = 0; + status.obpi = 0; +} + +LCD::LCD() { +} + +} diff --git a/gameboy/lcd/lcd.hpp b/gameboy/lcd/lcd.hpp new file mode 100755 index 00000000..f1b88115 --- /dev/null +++ b/gameboy/lcd/lcd.hpp @@ -0,0 +1,94 @@ +struct LCD : Processor, MMIO { + #include "mmio/mmio.hpp" + + struct Status { + unsigned lx; + unsigned wyc; + + //$ff40 LCDC + bool display_enable; + bool window_tilemap_select; + bool window_display_enable; + bool bg_tiledata_select; + bool bg_tilemap_select; + bool ob_size; + bool ob_enable; + bool bg_enable; + + //$ff41 STAT + bool interrupt_lyc; + bool interrupt_oam; + bool interrupt_vblank; + bool interrupt_hblank; + + //$ff42 SCY + uint8 scy; + + //$ff43 SCX + uint8 scx; + + //$ff44 LY + uint8 ly; + + //$ff45 LYC + uint8 lyc; + + //$ff4a WY + uint8 wy; + + //$ff4b WX + uint8 wx; + + //$ff4f VBK + bool vram_bank; + + //$ff68 BGPI + bool bgpi_increment; + uint6 bgpi; + + //$ff6a OBPI + bool obpi_increment; + uint8 obpi; + } status; + + uint16 screen[160 * 144]; + uint16 line[160]; + struct Origin { enum : unsigned { None, BG, BGP, OB }; }; + uint8 origin[160]; + + uint8 vram[16384]; //GB = 8192, GBC = 16384 + uint8 oam[160]; + uint8 bgp[4]; + uint8 obp[2][4]; + uint8 bgpd[64]; + uint8 obpd[64]; + + static void Main(); + void main(); + void add_clocks(unsigned clocks); + void scanline(); + void frame(); + + unsigned hflip(unsigned data) const; + + //dmg.cpp + void dmg_render(); + uint16 dmg_read_tile(bool select, unsigned x, unsigned y); + void dmg_render_bg(); + void dmg_render_window(); + void dmg_render_ob(); + + //cgb.cpp + void cgb_render(); + void cgb_read_tile(bool select, unsigned x, unsigned y, unsigned &tile, unsigned &attr, unsigned &data); + void cgb_render_bg(); + void cgb_render_window(); + void cgb_render_ob(); + + void power(); + + void serialize(serializer&); + LCD(); +}; + +extern LCD lcd; diff --git a/gameboy/lcd/mmio/mmio.cpp b/gameboy/lcd/mmio/mmio.cpp new file mode 100755 index 00000000..5b20fe70 --- /dev/null +++ b/gameboy/lcd/mmio/mmio.cpp @@ -0,0 +1,203 @@ +#ifdef LCD_CPP + +unsigned LCD::vram_addr(uint16 addr) const { + return (status.vram_bank * 0x2000) + (addr & 0x1fff); +} + +uint8 LCD::mmio_read(uint16 addr) { + if(addr >= 0x8000 && addr <= 0x9fff) return vram[vram_addr(addr)]; + if(addr >= 0xfe00 && addr <= 0xfe9f) return oam[addr & 0xff]; + + if(addr == 0xff40) { //LCDC + return (status.display_enable << 7) + | (status.window_tilemap_select << 6) + | (status.window_display_enable << 5) + | (status.bg_tiledata_select << 4) + | (status.bg_tilemap_select << 3) + | (status.ob_size << 2) + | (status.ob_enable << 1) + | (status.bg_enable << 0); + } + + if(addr == 0xff41) { //STAT + unsigned mode; + if(status.ly >= 144) mode = 1; //Vblank + else if(status.lx < 80) mode = 2; //OAM + else if(status.lx < 252) mode = 3; //LCD + else mode = 0; //Hblank + + return (status.interrupt_lyc << 6) + | (status.interrupt_oam << 5) + | (status.interrupt_vblank << 4) + | (status.interrupt_hblank << 3) + | ((status.ly == status.lyc) << 2) + | (mode << 0); + } + + if(addr == 0xff42) { //SCY + return status.scy; + } + + if(addr == 0xff43) { //SCX + return status.scx; + } + + if(addr == 0xff44) { //LY + return status.ly; + } + + if(addr == 0xff45) { //LYC + return status.lyc; + } + + if(addr == 0xff47) { //BGP + return (bgp[3] << 6) + | (bgp[2] << 4) + | (bgp[1] << 2) + | (bgp[0] << 0); + } + + if(addr == 0xff48) { //OBP0 + return (obp[0][3] << 6) + | (obp[0][2] << 4) + | (obp[0][1] << 2) + | (obp[0][0] << 0); + } + + if(addr == 0xff49) { //OBP1 + return (obp[1][3] << 6) + | (obp[1][2] << 4) + | (obp[1][1] << 2) + | (obp[1][0] << 0); + } + + if(addr == 0xff4a) { //WY + return status.wy; + } + + if(addr == 0xff4b) { //WX + return status.wx; + } + + if(addr == 0xff69) { //BGPD + return bgpd[status.bgpi]; + } + + if(addr == 0xff6b) { //OBPD + return obpd[status.obpi]; + } + + return 0x00; +} + +void LCD::mmio_write(uint16 addr, uint8 data) { + if(addr >= 0x8000 && addr <= 0x9fff) { vram[vram_addr(addr)] = data; return; } + if(addr >= 0xfe00 && addr <= 0xfe9f) { oam[addr & 0xff] = data; return; } + + if(addr == 0xff40) { //LCDC + if(status.display_enable == false && (data & 0x80)) { + status.lx = 0; //unverified behavior; fixes Super Mario Land 2 - Tree Zone + } + + status.display_enable = data & 0x80; + status.window_tilemap_select = data & 0x40; + status.window_display_enable = data & 0x20; + status.bg_tiledata_select = data & 0x10; + status.bg_tilemap_select = data & 0x08; + status.ob_size = data & 0x04; + status.ob_enable = data & 0x02; + status.bg_enable = data & 0x01; + return; + } + + if(addr == 0xff41) { //STAT + status.interrupt_lyc = data & 0x40; + status.interrupt_oam = data & 0x20; + status.interrupt_vblank = data & 0x10; + status.interrupt_hblank = data & 0x08; + return; + } + + if(addr == 0xff42) { //SCY + status.scy = data; + return; + } + + if(addr == 0xff43) { //SCX + status.scx = data; + return; + } + + if(addr == 0xff44) { //LY + status.ly = 0; + return; + } + + if(addr == 0xff45) { //LYC + status.lyc = data; + return; + } + + if(addr == 0xff47) { //BGP + bgp[3] = (data >> 6) & 3; + bgp[2] = (data >> 4) & 3; + bgp[1] = (data >> 2) & 3; + bgp[0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff48) { //OBP0 + obp[0][3] = (data >> 6) & 3; + obp[0][2] = (data >> 4) & 3; + obp[0][1] = (data >> 2) & 3; + obp[0][0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff49) { //OBP1 + obp[1][3] = (data >> 6) & 3; + obp[1][2] = (data >> 4) & 3; + obp[1][1] = (data >> 2) & 3; + obp[1][0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff4a) { //WY + status.wy = data; + return; + } + + if(addr == 0xff4b) { //WX + status.wx = data; + return; + } + + if(addr == 0xff4f) { //VBK + status.vram_bank = data & 1; + return; + } + + if(addr == 0xff68) { //BGPI + status.bgpi_increment = data & 0x80; + status.bgpi = data & 0x3f; + return; + } + + if(addr == 0xff69) { //BGPD + bgpd[status.bgpi] = data; + if(status.bgpi_increment) status.bgpi++; + return; + } + + if(addr == 0xff6a) { //OBPI + status.obpi_increment = data & 0x80; + status.obpi = data & 0x3f; + } + + if(addr == 0xff6b) { //OBPD + obpd[status.obpi] = data; + if(status.obpi_increment) status.obpi++; + } +} + +#endif diff --git a/gameboy/lcd/mmio/mmio.hpp b/gameboy/lcd/mmio/mmio.hpp new file mode 100755 index 00000000..d02d7559 --- /dev/null +++ b/gameboy/lcd/mmio/mmio.hpp @@ -0,0 +1,3 @@ +unsigned vram_addr(uint16 addr) const; +uint8 mmio_read(uint16 addr); +void mmio_write(uint16 addr, uint8 data); diff --git a/gameboy/lcd/serialization.cpp b/gameboy/lcd/serialization.cpp new file mode 100755 index 00000000..df4752aa --- /dev/null +++ b/gameboy/lcd/serialization.cpp @@ -0,0 +1,53 @@ +#ifdef LCD_CPP + +void LCD::serialize(serializer &s) { + Processor::serialize(s); + + s.array(screen); + s.array(line); + s.array(origin); + + s.array(vram); + s.array(oam); + s.array(bgp); + s.array(obp[0]); + s.array(obp[1]); + s.array(bgpd); + s.array(obpd); + + s.integer(status.lx); + s.integer(status.wyc); + + s.integer(status.display_enable); + s.integer(status.window_tilemap_select); + s.integer(status.window_display_enable); + s.integer(status.bg_tiledata_select); + s.integer(status.bg_tilemap_select); + s.integer(status.ob_size); + s.integer(status.ob_enable); + s.integer(status.bg_enable); + + s.integer(status.interrupt_lyc); + s.integer(status.interrupt_oam); + s.integer(status.interrupt_vblank); + s.integer(status.interrupt_hblank); + + s.integer(status.scy); + s.integer(status.scx); + + s.integer(status.ly); + s.integer(status.lyc); + + s.integer(status.wy); + s.integer(status.wx); + + s.integer(status.vram_bank); + + s.integer(status.bgpi_increment); + s.integer(status.bgpi); + + s.integer(status.obpi_increment); + s.integer(status.obpi); +} + +#endif diff --git a/gameboy/memory/memory.cpp b/gameboy/memory/memory.cpp new file mode 100755 index 00000000..ad281844 --- /dev/null +++ b/gameboy/memory/memory.cpp @@ -0,0 +1,69 @@ +#include + +#define MEMORY_CPP +namespace GameBoy { + +Unmapped unmapped; +Bus bus; + +uint8_t& Memory::operator[](unsigned addr) { + return data[addr]; +} + +void Memory::allocate(unsigned size_) { + free(); + size = size_; + data = new uint8_t[size](); +} + +void Memory::copy(const uint8_t *data_, unsigned size_) { + free(); + size = size_; + data = new uint8_t[size]; + memcpy(data, data_, size); +} + +void Memory::free() { + if(data) { + delete[] data; + data = 0; + } +} + +Memory::Memory() { + data = 0; + size = 0; +} + +Memory::~Memory() { + free(); +} + +// + +uint8 Bus::read(uint16 addr) { + uint8 data = mmio[addr]->mmio_read(addr); + + if(cheat.override[addr]) { + for(unsigned n = 0; n < cheat.size(); n++) { + if(cheat[n].addr == addr) { + if(cheat[n].comp > 255 || cheat[n].comp == data) { + data = cheat[n].data; + break; + } + } + } + } + + return data; +} + +void Bus::write(uint16 addr, uint8 data) { + mmio[addr]->mmio_write(addr, data); +} + +void Bus::power() { + for(unsigned n = 0x0000; n <= 0xffff; n++) mmio[n] = &unmapped; +} + +} diff --git a/gameboy/memory/memory.hpp b/gameboy/memory/memory.hpp new file mode 100755 index 00000000..3dfb8df9 --- /dev/null +++ b/gameboy/memory/memory.hpp @@ -0,0 +1,32 @@ +struct Memory { + uint8_t *data; + unsigned size; + + uint8_t& operator[](unsigned addr); + void allocate(unsigned size); + void copy(const uint8_t *data, unsigned size); + void free(); + Memory(); + ~Memory(); +}; + +struct MMIO { + virtual uint8 mmio_read(uint16 addr) = 0; + virtual void mmio_write(uint16 addr, uint8 data) = 0; +}; + +struct Unmapped : MMIO { + uint8 mmio_read(uint16) { return 0x00; } + void mmio_write(uint16, uint8) {} +}; + +struct Bus { + MMIO *mmio[65536]; + uint8 read(uint16 addr); + void write(uint16 addr, uint8 data); + + void power(); +}; + +extern Unmapped unmapped; +extern Bus bus; diff --git a/gameboy/scheduler/scheduler.cpp b/gameboy/scheduler/scheduler.cpp new file mode 100755 index 00000000..14bd7331 --- /dev/null +++ b/gameboy/scheduler/scheduler.cpp @@ -0,0 +1,35 @@ +#include + +#define SCHEDULER_CPP +namespace GameBoy { + +Scheduler scheduler; + +void Scheduler::enter() { + host_thread = co_active(); + co_switch(active_thread); +} + +void Scheduler::exit(ExitReason reason) { + exit_reason = reason; + active_thread = co_active(); + co_switch(host_thread); +} + +void Scheduler::swapto(Processor &p) { + active_thread = p.thread; + co_switch(active_thread); +} + +void Scheduler::init() { + host_thread = co_active(); + active_thread = cpu.thread; +} + +Scheduler::Scheduler() { + exit_reason = ExitReason::UnknownEvent; + host_thread = 0; + active_thread = 0; +} + +} diff --git a/gameboy/scheduler/scheduler.hpp b/gameboy/scheduler/scheduler.hpp new file mode 100755 index 00000000..ccdb78ec --- /dev/null +++ b/gameboy/scheduler/scheduler.hpp @@ -0,0 +1,17 @@ +struct Scheduler : property { + enum class SynchronizeMode : unsigned { None, CPU, All } sync; + enum class ExitReason : unsigned { UnknownEvent, StepEvent, FrameEvent, SynchronizeEvent }; + readonly exit_reason; + + cothread_t host_thread; + cothread_t active_thread; + + void enter(); + void exit(ExitReason); + void swapto(Processor&); + + void init(); + Scheduler(); +}; + +extern Scheduler scheduler; diff --git a/gameboy/system/bootrom-cgb.cpp b/gameboy/system/bootrom-cgb.cpp new file mode 100755 index 00000000..5d69bd05 --- /dev/null +++ b/gameboy/system/bootrom-cgb.cpp @@ -0,0 +1,135 @@ +#ifdef SYSTEM_CPP + +//SHA256 = 4bf5021be357ce523a59ac5f4efff5d6371ae50112a6db0adf4a75916ad760a9 +const uint8_t System::BootROM::cgb[2048] = { + 0x31,0xfe,0xff,0x3e,0x02,0xc3,0x7c,0x00,0xd3,0x00,0x98,0xa0,0x12,0xd3,0x00,0x80, + 0x00,0x40,0x1e,0x53,0xd0,0x00,0x1f,0x42,0x1c,0x00,0x14,0x2a,0x4d,0x19,0x8c,0x7e, + 0x00,0x7c,0x31,0x6e,0x4a,0x45,0x52,0x4a,0x00,0x00,0xff,0x53,0x1f,0x7c,0xff,0x03, + 0x1f,0x00,0xff,0x1f,0xa7,0x00,0xef,0x1b,0x1f,0x00,0xef,0x1b,0x00,0x7c,0x00,0x00, + 0xff,0x03,0xce,0xed,0x66,0x66,0xcc,0x0d,0x00,0x0b,0x03,0x73,0x00,0x83,0x00,0x0c, + 0x00,0x0d,0x00,0x08,0x11,0x1f,0x88,0x89,0x00,0x0e,0xdc,0xcc,0x6e,0xe6,0xdd,0xdd, + 0xd9,0x99,0xbb,0xbb,0x67,0x63,0x6e,0x0e,0xec,0xcc,0xdd,0xdc,0x99,0x9f,0xbb,0xb9, + 0x33,0x3e,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,0x58,0x43,0xe0,0x70,0x3e,0xfc, + 0xe0,0x47,0xcd,0x75,0x02,0xcd,0x00,0x02,0x26,0xd0,0xcd,0x03,0x02,0x21,0x00,0xfe, + 0x0e,0xa0,0xaf,0x22,0x0d,0x20,0xfc,0x11,0x04,0x01,0x21,0x10,0x80,0x4c,0x1a,0xe2, + 0x0c,0xcd,0xc6,0x03,0xcd,0xc7,0x03,0x13,0x7b,0xfe,0x34,0x20,0xf1,0x11,0x72,0x00, + 0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,0xcd,0xf0,0x03,0x3e,0x01,0xe0,0x4f, + 0x3e,0x91,0xe0,0x40,0x21,0xb2,0x98,0x06,0x4e,0x0e,0x44,0xcd,0x91,0x02,0xaf,0xe0, + 0x4f,0x0e,0x80,0x21,0x42,0x00,0x06,0x18,0xf2,0x0c,0xbe,0x20,0xfe,0x23,0x05,0x20, + 0xf7,0x21,0x34,0x01,0x06,0x19,0x78,0x86,0x2c,0x05,0x20,0xfb,0x86,0x20,0xfe,0xcd, + 0x1c,0x03,0x18,0x02,0x00,0x00,0xcd,0xd0,0x05,0xaf,0xe0,0x70,0x3e,0x11,0xe0,0x50, + 0x21,0x00,0x80,0xaf,0x22,0xcb,0x6c,0x28,0xfb,0xc9,0x2a,0x12,0x13,0x0d,0x20,0xfa, + 0xc9,0xe5,0x21,0x0f,0xff,0xcb,0x86,0xcb,0x46,0x28,0xfc,0xe1,0xc9,0x11,0x00,0xff, + 0x21,0x03,0xd0,0x0e,0x0f,0x3e,0x30,0x12,0x3e,0x20,0x12,0x1a,0x2f,0xa1,0xcb,0x37, + 0x47,0x3e,0x10,0x12,0x1a,0x2f,0xa1,0xb0,0x4f,0x7e,0xa9,0xe6,0xf0,0x47,0x2a,0xa9, + 0xa1,0xb0,0x32,0x47,0x79,0x77,0x3e,0x30,0x12,0xc9,0x3e,0x80,0xe0,0x68,0xe0,0x6a, + 0x0e,0x6b,0x2a,0xe2,0x05,0x20,0xfb,0x4a,0x09,0x43,0x0e,0x69,0x2a,0xe2,0x05,0x20, + 0xfb,0xc9,0xc5,0xd5,0xe5,0x21,0x00,0xd8,0x06,0x01,0x16,0x3f,0x1e,0x40,0xcd,0x4a, + 0x02,0xe1,0xd1,0xc1,0xc9,0x3e,0x80,0xe0,0x26,0xe0,0x11,0x3e,0xf3,0xe0,0x12,0xe0, + 0x25,0x3e,0x77,0xe0,0x24,0x21,0x30,0xff,0xaf,0x0e,0x10,0x22,0x2f,0x0d,0x20,0xfb, + 0xc9,0xcd,0x11,0x02,0xcd,0x62,0x02,0x79,0xfe,0x38,0x20,0x14,0xe5,0xaf,0xe0,0x4f, + 0x21,0xa7,0x99,0x3e,0x38,0x22,0x3c,0xfe,0x3f,0x20,0xfa,0x3e,0x01,0xe0,0x4f,0xe1, + 0xc5,0xe5,0x21,0x43,0x01,0xcb,0x7e,0xcc,0x89,0x05,0xe1,0xc1,0xcd,0x11,0x02,0x79, + 0xd6,0x30,0xd2,0x06,0x03,0x79,0xfe,0x01,0xca,0x06,0x03,0x7d,0xfe,0xd1,0x28,0x21, + 0xc5,0x06,0x03,0x0e,0x01,0x16,0x03,0x7e,0xe6,0xf8,0xb1,0x22,0x15,0x20,0xf8,0x0c, + 0x79,0xfe,0x06,0x20,0xf0,0x11,0x11,0x00,0x19,0x05,0x20,0xe7,0x11,0xa1,0xff,0x19, + 0xc1,0x04,0x78,0x1e,0x83,0xfe,0x62,0x28,0x06,0x1e,0xc1,0xfe,0x64,0x20,0x07,0x7b, + 0xe0,0x13,0x3e,0x87,0xe0,0x14,0xfa,0x02,0xd0,0xfe,0x00,0x28,0x0a,0x3d,0xea,0x02, + 0xd0,0x79,0xfe,0x01,0xca,0x91,0x02,0x0d,0xc2,0x91,0x02,0xc9,0x0e,0x26,0xcd,0x4a, + 0x03,0xcd,0x11,0x02,0xcd,0x62,0x02,0x0d,0x20,0xf4,0xcd,0x11,0x02,0x3e,0x01,0xe0, + 0x4f,0xcd,0x3e,0x03,0xcd,0x41,0x03,0xaf,0xe0,0x4f,0xcd,0x3e,0x03,0xc9,0x21,0x08, + 0x00,0x11,0x51,0xff,0x0e,0x05,0xcd,0x0a,0x02,0xc9,0xc5,0xd5,0xe5,0x21,0x40,0xd8, + 0x0e,0x20,0x7e,0xe6,0x1f,0xfe,0x1f,0x28,0x01,0x3c,0x57,0x2a,0x07,0x07,0x07,0xe6, + 0x07,0x47,0x3a,0x07,0x07,0x07,0xe6,0x18,0xb0,0xfe,0x1f,0x28,0x01,0x3c,0x0f,0x0f, + 0x0f,0x47,0xe6,0xe0,0xb2,0x22,0x78,0xe6,0x03,0x5f,0x7e,0x0f,0x0f,0xe6,0x1f,0xfe, + 0x1f,0x28,0x01,0x3c,0x07,0x07,0xb3,0x22,0x0d,0x20,0xc7,0xe1,0xd1,0xc1,0xc9,0x0e, + 0x00,0x1a,0xe6,0xf0,0xcb,0x49,0x28,0x02,0xcb,0x37,0x47,0x23,0x7e,0xb0,0x22,0x1a, + 0xe6,0x0f,0xcb,0x49,0x20,0x02,0xcb,0x37,0x47,0x23,0x7e,0xb0,0x22,0x13,0xcb,0x41, + 0x28,0x0d,0xd5,0x11,0xf8,0xff,0xcb,0x49,0x28,0x03,0x11,0x08,0x00,0x19,0xd1,0x0c, + 0x79,0xfe,0x18,0x20,0xcc,0xc9,0x47,0xd5,0x16,0x04,0x58,0xcb,0x10,0x17,0xcb,0x13, + 0x17,0x15,0x20,0xf6,0xd1,0x22,0x23,0x22,0x23,0xc9,0x3e,0x19,0xea,0x10,0x99,0x21, + 0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,0xf9,0x2e,0x0f,0x18,0xf3,0xc9, + 0x3e,0x01,0xe0,0x4f,0xcd,0x00,0x02,0x11,0x07,0x06,0x21,0x80,0x80,0x0e,0xc0,0x1a, + 0x22,0x23,0x22,0x23,0x13,0x0d,0x20,0xf7,0x11,0x04,0x01,0xcd,0x8f,0x03,0x01,0xa8, + 0xff,0x09,0xcd,0x8f,0x03,0x01,0xf8,0xff,0x09,0x11,0x72,0x00,0x0e,0x08,0x23,0x1a, + 0x22,0x13,0x0d,0x20,0xf9,0x21,0xc2,0x98,0x06,0x08,0x3e,0x08,0x0e,0x10,0x22,0x0d, + 0x20,0xfc,0x11,0x10,0x00,0x19,0x05,0x20,0xf3,0xaf,0xe0,0x4f,0x21,0xc2,0x98,0x3e, + 0x08,0x22,0x3c,0xfe,0x18,0x20,0x02,0x2e,0xe2,0xfe,0x28,0x20,0x03,0x21,0x02,0x99, + 0xfe,0x38,0x20,0xed,0x21,0xd8,0x08,0x11,0x40,0xd8,0x06,0x08,0x3e,0xff,0x12,0x13, + 0x12,0x13,0x0e,0x02,0xcd,0x0a,0x02,0x3e,0x00,0x12,0x13,0x12,0x13,0x13,0x13,0x05, + 0x20,0xea,0xcd,0x62,0x02,0x21,0x4b,0x01,0x7e,0xfe,0x33,0x20,0x0b,0x2e,0x44,0x1e, + 0x30,0x2a,0xbb,0x20,0x49,0x1c,0x18,0x04,0x2e,0x4b,0x1e,0x01,0x2a,0xbb,0x20,0x3e, + 0x2e,0x34,0x01,0x10,0x00,0x2a,0x80,0x47,0x0d,0x20,0xfa,0xea,0x00,0xd0,0x21,0xc7, + 0x06,0x0e,0x00,0x2a,0xb8,0x28,0x08,0x0c,0x79,0xfe,0x4f,0x20,0xf6,0x18,0x1f,0x79, + 0xd6,0x41,0x38,0x1c,0x21,0x16,0x07,0x16,0x00,0x5f,0x19,0xfa,0x37,0x01,0x57,0x7e, + 0xba,0x28,0x0d,0x11,0x0e,0x00,0x19,0x79,0x83,0x4f,0xd6,0x5e,0x38,0xed,0x0e,0x00, + 0x21,0x33,0x07,0x06,0x00,0x09,0x7e,0xe6,0x1f,0xea,0x08,0xd0,0x7e,0xe6,0xe0,0x07, + 0x07,0x07,0xea,0x0b,0xd0,0xcd,0xe9,0x04,0xc9,0x11,0x91,0x07,0x21,0x00,0xd9,0xfa, + 0x0b,0xd0,0x47,0x0e,0x1e,0xcb,0x40,0x20,0x02,0x13,0x13,0x1a,0x22,0x20,0x02,0x1b, + 0x1b,0xcb,0x48,0x20,0x02,0x13,0x13,0x1a,0x22,0x13,0x13,0x20,0x02,0x1b,0x1b,0xcb, + 0x50,0x28,0x05,0x1b,0x2b,0x1a,0x22,0x13,0x1a,0x22,0x13,0x0d,0x20,0xd7,0x21,0x00, + 0xd9,0x11,0x00,0xda,0xcd,0x64,0x05,0xc9,0x21,0x12,0x00,0xfa,0x05,0xd0,0x07,0x07, + 0x06,0x00,0x4f,0x09,0x11,0x40,0xd8,0x06,0x08,0xe5,0x0e,0x02,0xcd,0x0a,0x02,0x13, + 0x13,0x13,0x13,0x13,0x13,0xe1,0x05,0x20,0xf0,0x11,0x42,0xd8,0x0e,0x02,0xcd,0x0a, + 0x02,0x11,0x4a,0xd8,0x0e,0x02,0xcd,0x0a,0x02,0x2b,0x2b,0x11,0x44,0xd8,0x0e,0x02, + 0xcd,0x0a,0x02,0xc9,0x0e,0x60,0x2a,0xe5,0xc5,0x21,0xe8,0x07,0x06,0x00,0x4f,0x09, + 0x0e,0x08,0xcd,0x0a,0x02,0xc1,0xe1,0x0d,0x20,0xec,0xc9,0xfa,0x08,0xd0,0x11,0x18, + 0x00,0x3c,0x3d,0x28,0x03,0x19,0x20,0xfa,0xc9,0xcd,0x1d,0x02,0x78,0xe6,0xff,0x28, + 0x0f,0x21,0xe4,0x08,0x06,0x00,0x2a,0xb9,0x28,0x08,0x04,0x78,0xfe,0x0c,0x20,0xf6, + 0x18,0x2d,0x78,0xea,0x05,0xd0,0x3e,0x1e,0xea,0x02,0xd0,0x11,0x0b,0x00,0x19,0x56, + 0x7a,0xe6,0x1f,0x5f,0x21,0x08,0xd0,0x3a,0x22,0x7b,0x77,0x7a,0xe6,0xe0,0x07,0x07, + 0x07,0x5f,0x21,0x0b,0xd0,0x3a,0x22,0x7b,0x77,0xcd,0xe9,0x04,0xcd,0x28,0x05,0xc9, + 0xcd,0x11,0x02,0xfa,0x43,0x01,0xcb,0x7f,0x28,0x04,0xe0,0x4c,0x18,0x28,0x3e,0x04, + 0xe0,0x4c,0x3e,0x01,0xe0,0x6c,0x21,0x00,0xda,0xcd,0x7b,0x05,0x06,0x10,0x16,0x00, + 0x1e,0x08,0xcd,0x4a,0x02,0x21,0x7a,0x00,0xfa,0x00,0xd0,0x47,0x0e,0x02,0x2a,0xb8, + 0xcc,0xda,0x03,0x0d,0x20,0xf8,0xc9,0x01,0x0f,0x3f,0x7e,0xff,0xff,0xc0,0x00,0xc0, + 0xf0,0xf1,0x03,0x7c,0xfc,0xfe,0xfe,0x03,0x07,0x07,0x0f,0xe0,0xe0,0xf0,0xf0,0x1e, + 0x3e,0x7e,0xfe,0x0f,0x0f,0x1f,0x1f,0xff,0xff,0x00,0x00,0x01,0x01,0x01,0x03,0xff, + 0xff,0xe1,0xe0,0xc0,0xf0,0xf9,0xfb,0x1f,0x7f,0xf8,0xe0,0xf3,0xfd,0x3e,0x1e,0xe0, + 0xf0,0xf9,0x7f,0x3e,0x7c,0xf8,0xe0,0xf8,0xf0,0xf0,0xf8,0x00,0x00,0x7f,0x7f,0x07, + 0x0f,0x9f,0xbf,0x9e,0x1f,0xff,0xff,0x0f,0x1e,0x3e,0x3c,0xf1,0xfb,0x7f,0x7f,0xfe, + 0xde,0xdf,0x9f,0x1f,0x3f,0x3e,0x3c,0xf8,0xf8,0x00,0x00,0x03,0x03,0x07,0x07,0xff, + 0xff,0xc1,0xc0,0xf3,0xe7,0xf7,0xf3,0xc0,0xc0,0xc0,0xc0,0x1f,0x1f,0x1e,0x3e,0x3f, + 0x1f,0x3e,0x3e,0x80,0x00,0x00,0x00,0x7c,0x1f,0x07,0x00,0x0f,0xff,0xfe,0x00,0x7c, + 0xf8,0xf0,0x00,0x1f,0x0f,0x0f,0x00,0x7c,0xf8,0xf8,0x00,0x3f,0x3e,0x1c,0x00,0x0f, + 0x0f,0x0f,0x00,0x7c,0xff,0xff,0x00,0x00,0xf8,0xf8,0x00,0x07,0x0f,0x0f,0x00,0x81, + 0xff,0xff,0x00,0xf3,0xe1,0x80,0x00,0xe0,0xff,0x7f,0x00,0xfc,0xf0,0xc0,0x00,0x3e, + 0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x16,0x36,0xd1,0xdb,0xf2,0x3c,0x8c, + 0x92,0x3d,0x5c,0x58,0xc9,0x3e,0x70,0x1d,0x59,0x69,0x19,0x35,0xa8,0x14,0xaa,0x75, + 0x95,0x99,0x34,0x6f,0x15,0xff,0x97,0x4b,0x90,0x17,0x10,0x39,0xf7,0xf6,0xa2,0x49, + 0x4e,0x43,0x68,0xe0,0x8b,0xf0,0xce,0x0c,0x29,0xe8,0xb7,0x86,0x9a,0x52,0x01,0x9d, + 0x71,0x9c,0xbd,0x5d,0x6d,0x67,0x3f,0x6b,0xb3,0x46,0x28,0xa5,0xc6,0xd3,0x27,0x61, + 0x18,0x66,0x6a,0xbf,0x0d,0xf4,0x42,0x45,0x46,0x41,0x41,0x52,0x42,0x45,0x4b,0x45, + 0x4b,0x20,0x52,0x2d,0x55,0x52,0x41,0x52,0x20,0x49,0x4e,0x41,0x49,0x4c,0x49,0x43, + 0x45,0x20,0x52,0x7c,0x08,0x12,0xa3,0xa2,0x07,0x87,0x4b,0x20,0x12,0x65,0xa8,0x16, + 0xa9,0x86,0xb1,0x68,0xa0,0x87,0x66,0x12,0xa1,0x30,0x3c,0x12,0x85,0x12,0x64,0x1b, + 0x07,0x06,0x6f,0x6e,0x6e,0xae,0xaf,0x6f,0xb2,0xaf,0xb2,0xa8,0xab,0x6f,0xaf,0x86, + 0xae,0xa2,0xa2,0x12,0xaf,0x13,0x12,0xa1,0x6e,0xaf,0xaf,0xad,0x06,0x4c,0x6e,0xaf, + 0xaf,0x12,0x7c,0xac,0xa8,0x6a,0x6e,0x13,0xa0,0x2d,0xa8,0x2b,0xac,0x64,0xac,0x6d, + 0x87,0xbc,0x60,0xb4,0x13,0x72,0x7c,0xb5,0xae,0xae,0x7c,0x7c,0x65,0xa2,0x6c,0x64, + 0x85,0x80,0xb0,0x40,0x88,0x20,0x68,0xde,0x00,0x70,0xde,0x20,0x78,0x20,0x20,0x38, + 0x20,0xb0,0x90,0x20,0xb0,0xa0,0xe0,0xb0,0xc0,0x98,0xb6,0x48,0x80,0xe0,0x50,0x1e, + 0x1e,0x58,0x20,0xb8,0xe0,0x88,0xb0,0x10,0x20,0x00,0x10,0x20,0xe0,0x18,0xe0,0x18, + 0x00,0x18,0xe0,0x20,0xa8,0xe0,0x20,0x18,0xe0,0x00,0x20,0x18,0xd8,0xc8,0x18,0xe0, + 0x00,0xe0,0x40,0x28,0x28,0x28,0x18,0xe0,0x60,0x20,0x18,0xe0,0x00,0x00,0x08,0xe0, + 0x18,0x30,0xd0,0xd0,0xd0,0x20,0xe0,0xe8,0xff,0x7f,0xbf,0x32,0xd0,0x00,0x00,0x00, + 0x9f,0x63,0x79,0x42,0xb0,0x15,0xcb,0x04,0xff,0x7f,0x31,0x6e,0x4a,0x45,0x00,0x00, + 0xff,0x7f,0xef,0x1b,0x00,0x02,0x00,0x00,0xff,0x7f,0x1f,0x42,0xf2,0x1c,0x00,0x00, + 0xff,0x7f,0x94,0x52,0x4a,0x29,0x00,0x00,0xff,0x7f,0xff,0x03,0x2f,0x01,0x00,0x00, + 0xff,0x7f,0xef,0x03,0xd6,0x01,0x00,0x00,0xff,0x7f,0xb5,0x42,0xc8,0x3d,0x00,0x00, + 0x74,0x7e,0xff,0x03,0x80,0x01,0x00,0x00,0xff,0x67,0xac,0x77,0x13,0x1a,0x6b,0x2d, + 0xd6,0x7e,0xff,0x4b,0x75,0x21,0x00,0x00,0xff,0x53,0x5f,0x4a,0x52,0x7e,0x00,0x00, + 0xff,0x4f,0xd2,0x7e,0x4c,0x3a,0xe0,0x1c,0xed,0x03,0xff,0x7f,0x5f,0x25,0x00,0x00, + 0x6a,0x03,0x1f,0x02,0xff,0x03,0xff,0x7f,0xff,0x7f,0xdf,0x01,0x12,0x01,0x00,0x00, + 0x1f,0x23,0x5f,0x03,0xf2,0x00,0x09,0x00,0xff,0x7f,0xea,0x03,0x1f,0x01,0x00,0x00, + 0x9f,0x29,0x1a,0x00,0x0c,0x00,0x00,0x00,0xff,0x7f,0x7f,0x02,0x1f,0x00,0x00,0x00, + 0xff,0x7f,0xe0,0x03,0x06,0x02,0x20,0x01,0xff,0x7f,0xeb,0x7e,0x1f,0x00,0x00,0x7c, + 0xff,0x7f,0xff,0x3f,0x00,0x7e,0x1f,0x00,0xff,0x7f,0xff,0x03,0x1f,0x00,0x00,0x00, + 0xff,0x03,0x1f,0x00,0x0c,0x00,0x00,0x00,0xff,0x7f,0x3f,0x03,0x93,0x01,0x00,0x00, + 0x00,0x00,0x00,0x42,0x7f,0x03,0xff,0x7f,0xff,0x7f,0x8c,0x7e,0x00,0x7c,0x00,0x00, + 0xff,0x7f,0xef,0x1b,0x80,0x61,0x00,0x00,0xff,0x7f,0x00,0x7c,0xe0,0x03,0x1f,0x7c, + 0x1f,0x00,0xff,0x03,0x40,0x41,0x42,0x20,0x21,0x22,0x80,0x81,0x82,0x10,0x11,0x12, + 0x12,0xb0,0x79,0xb8,0xad,0x16,0x17,0x07,0xba,0x05,0x7c,0x13,0x00,0x00,0x00,0x00, +}; + +#endif diff --git a/gameboy/system/bootrom-dmg.cpp b/gameboy/system/bootrom-dmg.cpp new file mode 100755 index 00000000..54f02748 --- /dev/null +++ b/gameboy/system/bootrom-dmg.cpp @@ -0,0 +1,23 @@ +#ifdef SYSTEM_CPP + +//SHA256 = cf053eccb4ccafff9e67339d4e78e98dce7d1ed59be819d2a1ba2232c6fce1c7 +const uint8_t System::BootROM::dmg[256] = { + 0x31,0xfe,0xff,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb,0x21,0x26,0xff,0x0e, + 0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77,0x77,0x3e,0xfc,0xe0, + 0x47,0x11,0x04,0x01,0x21,0x10,0x80,0x1a,0xcd,0x95,0x00,0xcd,0x96,0x00,0x13,0x7b, + 0xfe,0x34,0x20,0xf3,0x11,0xd8,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9, + 0x3e,0x19,0xea,0x10,0x99,0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20, + 0xf9,0x2e,0x0f,0x18,0xf3,0x67,0x3e,0x64,0x57,0xe0,0x42,0x3e,0x91,0xe0,0x40,0x04, + 0x1e,0x02,0x0e,0x0c,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x0d,0x20,0xf7,0x1d,0x20,0xf2, + 0x0e,0x13,0x24,0x7c,0x1e,0x83,0xfe,0x62,0x28,0x06,0x1e,0xc1,0xfe,0x64,0x20,0x06, + 0x7b,0xe2,0x0c,0x3e,0x87,0xe2,0xf0,0x42,0x90,0xe0,0x42,0x15,0x20,0xd2,0x05,0x20, + 0x4f,0x16,0x20,0x18,0xcb,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17, + 0x05,0x20,0xf5,0x22,0x23,0x22,0x23,0xc9,0xce,0xed,0x66,0x66,0xcc,0x0d,0x00,0x0b, + 0x03,0x73,0x00,0x83,0x00,0x0c,0x00,0x0d,0x00,0x08,0x11,0x1f,0x88,0x89,0x00,0x0e, + 0xdc,0xcc,0x6e,0xe6,0xdd,0xdd,0xd9,0x99,0xbb,0xbb,0x67,0x63,0x6e,0x0e,0xec,0xcc, + 0xdd,0xdc,0x99,0x9f,0xbb,0xb9,0x33,0x3e,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c, + 0x21,0x04,0x01,0x11,0xa8,0x00,0x1a,0x13,0xbe,0x20,0xfe,0x23,0x7d,0xfe,0x34,0x20, + 0xf5,0x06,0x19,0x78,0x86,0x23,0x05,0x20,0xfb,0x86,0x20,0xfe,0x3e,0x01,0xe0,0x50, +}; + +#endif diff --git a/gameboy/system/bootrom-sgb.cpp b/gameboy/system/bootrom-sgb.cpp new file mode 100755 index 00000000..71c0952a --- /dev/null +++ b/gameboy/system/bootrom-sgb.cpp @@ -0,0 +1,23 @@ +#ifdef SYSTEM_CPP + +//SHA256 = 0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360 +const uint8_t System::BootROM::sgb[256] = { + 0x31,0xfe,0xff,0x3e,0x30,0xe0,0x00,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb, + 0x21,0x26,0xff,0x0e,0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77, + 0x77,0x3e,0xfc,0xe0,0x47,0x21,0x5f,0xc0,0x0e,0x08,0xaf,0x32,0x0d,0x20,0xfc,0x11, + 0x4f,0x01,0x3e,0xfb,0x0e,0x06,0xf5,0x06,0x00,0x1a,0x1b,0x32,0x80,0x47,0x0d,0x20, + 0xf8,0x32,0xf1,0x32,0x0e,0x0e,0xd6,0x02,0xfe,0xef,0x20,0xea,0x11,0x04,0x01,0x21, + 0x10,0x80,0x1a,0xcd,0xd3,0x00,0xcd,0xd4,0x00,0x13,0x7b,0xfe,0x34,0x20,0xf3,0x11, + 0xe6,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,0x3e,0x19,0xea,0x10,0x99, + 0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,0xf9,0x2e,0x0f,0x18,0xf3, + 0x3e,0x91,0xe0,0x40,0x21,0x00,0xc0,0x0e,0x00,0x3e,0x00,0xe2,0x3e,0x30,0xe2,0x06, + 0x10,0x1e,0x08,0x2a,0x57,0xcb,0x42,0x3e,0x10,0x20,0x02,0x3e,0x20,0xe2,0x3e,0x30, + 0xe2,0xcb,0x1a,0x1d,0x20,0xef,0x05,0x20,0xe8,0x3e,0x20,0xe2,0x3e,0x30,0xe2,0xcd, + 0xc2,0x00,0x7d,0xfe,0x60,0x20,0xd2,0x0e,0x13,0x3e,0xc1,0xe2,0x0c,0x3e,0x07,0xe2, + 0x18,0x3a,0x16,0x04,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x1e,0x00,0x1d,0x20,0xfd,0x15, + 0x20,0xf2,0xc9,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17,0x05,0x20, + 0xf5,0x22,0x23,0x22,0x23,0xc9,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x01,0xe0,0x50, +}; + +#endif diff --git a/gameboy/system/serialization.cpp b/gameboy/system/serialization.cpp new file mode 100755 index 00000000..c7ca0f8b --- /dev/null +++ b/gameboy/system/serialization.cpp @@ -0,0 +1,64 @@ +#ifdef SYSTEM_CPP + +serializer System::serialize() { + serializer s(serialize_size); + + unsigned signature = 0x31545342, version = Info::SerializerVersion, crc32 = 0; + char description[512]; + memset(&description, 0, sizeof description); + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(description); + + serialize_all(s); + return s; +} + +bool System::unserialize(serializer &s) { + unsigned signature, version, crc32; + char description[512]; + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(description); + + if(signature != 0x31545342) return false; + if(version != Info::SerializerVersion) return false; +//if(crc32 != 0) return false; + + power(); + serialize_all(s); + return true; +} + +void System::serialize(serializer &s) { + s.integer(clocks_executed); +} + +void System::serialize_all(serializer &s) { + cartridge.serialize(s); + system.serialize(s); + cpu.serialize(s); + apu.serialize(s); + lcd.serialize(s); +} + +void System::serialize_init() { + serializer s; + + unsigned signature = 0, version = 0, crc32 = 0; + char description[512]; + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(description); + + serialize_all(s); + serialize_size = s.size(); +} + +#endif diff --git a/gameboy/system/system.cpp b/gameboy/system/system.cpp new file mode 100755 index 00000000..0d6567bd --- /dev/null +++ b/gameboy/system/system.cpp @@ -0,0 +1,57 @@ +#include + +#define SYSTEM_CPP +namespace GameBoy { + +#include "bootrom-dmg.cpp" +#include "bootrom-sgb.cpp" +#include "bootrom-cgb.cpp" +#include "serialization.cpp" +System system; + +void System::run() { + scheduler.sync = Scheduler::SynchronizeMode::None; + + scheduler.enter(); + if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) { + } +} + +void System::runtosave() { + scheduler.sync = Scheduler::SynchronizeMode::CPU; + runthreadtosave(); + + scheduler.active_thread = lcd.thread; + runthreadtosave(); +} + +void System::runthreadtosave() { + while(true) { + scheduler.enter(); + if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break; + if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) { + } + } +} + +void System::init() { + assert(interface != 0); +} + +void System::load(Revision revision) { + this->revision = revision; + serialize_init(); +} + +void System::power() { + bus.power(); + cartridge.power(); + cpu.power(); + apu.power(); + lcd.power(); + scheduler.init(); + + clocks_executed = 0; +} + +} diff --git a/gameboy/system/system.hpp b/gameboy/system/system.hpp new file mode 100755 index 00000000..18ad757f --- /dev/null +++ b/gameboy/system/system.hpp @@ -0,0 +1,47 @@ +class Interface; + +enum class Input : unsigned { + Up, Down, Left, Right, B, A, Select, Start, +}; + +struct System : property { + enum class Revision : unsigned { + GameBoy, + SuperGameBoy, + GameBoyColor, + }; + readonly revision; + inline bool dmg() const { return revision == Revision::GameBoy; } + inline bool sgb() const { return revision == Revision::SuperGameBoy; } + inline bool cgb() const { return revision == Revision::GameBoyColor; } + + struct BootROM { + static const uint8 dmg[ 256]; + static const uint8 sgb[ 256]; + static const uint8 cgb[2048]; + } bootROM; + + void run(); + void runtosave(); + void runthreadtosave(); + + void init(); + void load(Revision); + void power(); + + unsigned clocks_executed; + + //serialization.cpp + unsigned serialize_size; + + serializer serialize(); + bool unserialize(serializer&); + + void serialize(serializer&); + void serialize_all(serializer&); + void serialize_init(); +}; + +#include + +extern System system; diff --git a/gameboy/video/video.cpp b/gameboy/video/video.cpp new file mode 100755 index 00000000..3cbcd249 --- /dev/null +++ b/gameboy/video/video.cpp @@ -0,0 +1,82 @@ +#include + +#define VIDEO_CPP +namespace GameBoy { + +Video video; + +unsigned Video::palette_dmg(unsigned color) const { + unsigned R = monochrome[color][0] * 1023.0; + unsigned G = monochrome[color][1] * 1023.0; + unsigned B = monochrome[color][2] * 1023.0; + + return (R << 20) + (G << 10) + (B << 0); +} + +unsigned Video::palette_sgb(unsigned color) const { + unsigned R = (3 - color) * 341; + unsigned G = (3 - color) * 341; + unsigned B = (3 - color) * 341; + + return (R << 20) + (G << 10) + (B << 0); +} + +unsigned Video::palette_cgb(unsigned color) const { + unsigned r = (color >> 0) & 31; + unsigned g = (color >> 5) & 31; + unsigned b = (color >> 10) & 31; + + unsigned R = (r * 26 + g * 4 + b * 2); + unsigned G = ( g * 24 + b * 8); + unsigned B = (r * 6 + g * 4 + b * 22); + + R = min(960, R); + G = min(960, G); + B = min(960, B); + + return (R << 20) + (G << 10) + (B << 0); +} + +void Video::generate(Format format) { + if(system.dmg()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_dmg(n); + if(system.sgb()) for(unsigned n = 0; n < 4; n++) palette[n] = palette_sgb(n); + if(system.cgb()) for(unsigned n = 0; n < (1 << 15); n++) palette[n] = palette_cgb(n); + + if(format == Format::RGB24) { + for(unsigned n = 0; n < (1 << 15); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff); + } + } + + if(format == Format::RGB16) { + for(unsigned n = 0; n < (1 << 15); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f); + } + } + + if(format == Format::RGB15) { + for(unsigned n = 0; n < (1 << 15); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f); + } + } +} + +Video::Video() { + palette = new unsigned[1 << 15]; +} + +Video::~Video() { + delete[] palette; +} + +const double Video::monochrome[4][3] = { + { 0.605, 0.734, 0.059 }, + { 0.543, 0.672, 0.059 }, + { 0.188, 0.383, 0.188 }, + { 0.059, 0.219, 0.059 }, +}; + +} diff --git a/gameboy/video/video.hpp b/gameboy/video/video.hpp new file mode 100755 index 00000000..131b2868 --- /dev/null +++ b/gameboy/video/video.hpp @@ -0,0 +1,17 @@ +struct Video { + enum class Format : unsigned { RGB30, RGB24, RGB16, RGB15 }; + unsigned *palette; + + unsigned palette_dmg(unsigned color) const; + unsigned palette_sgb(unsigned color) const; + unsigned palette_cgb(unsigned color) const; + + void generate(Format format); + Video(); + ~Video(); + +private: + static const double monochrome[4][3]; +}; + +extern Video video; diff --git a/libco/amd64.c b/libco/amd64.c new file mode 100755 index 00000000..5f1cfca9 --- /dev/null +++ b/libco/amd64.c @@ -0,0 +1,104 @@ +/* + libco.amd64 (2009-10-12) + author: byuu + license: public domain +*/ + +#define LIBCO_C +#include "libco.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static thread_local long long co_active_buffer[64]; +static thread_local cothread_t co_active_handle = 0; +static void (*co_swap)(cothread_t, cothread_t) = 0; + +#ifdef _WIN32 + //ABI: Win64 + static unsigned char co_swap_function[] = { + 0x48, 0x89, 0x22, 0x48, 0x8B, 0x21, 0x58, 0x48, 0x89, 0x6A, 0x08, 0x48, 0x89, 0x72, 0x10, 0x48, + 0x89, 0x7A, 0x18, 0x48, 0x89, 0x5A, 0x20, 0x4C, 0x89, 0x62, 0x28, 0x4C, 0x89, 0x6A, 0x30, 0x4C, + 0x89, 0x72, 0x38, 0x4C, 0x89, 0x7A, 0x40, 0x48, 0x81, 0xC2, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83, + 0xE2, 0xF0, 0x0F, 0x29, 0x32, 0x0F, 0x29, 0x7A, 0x10, 0x44, 0x0F, 0x29, 0x42, 0x20, 0x44, 0x0F, + 0x29, 0x4A, 0x30, 0x44, 0x0F, 0x29, 0x52, 0x40, 0x44, 0x0F, 0x29, 0x5A, 0x50, 0x44, 0x0F, 0x29, + 0x62, 0x60, 0x44, 0x0F, 0x29, 0x6A, 0x70, 0x44, 0x0F, 0x29, 0xB2, 0x80, 0x00, 0x00, 0x00, 0x44, + 0x0F, 0x29, 0xBA, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x69, 0x08, 0x48, 0x8B, 0x71, 0x10, 0x48, + 0x8B, 0x79, 0x18, 0x48, 0x8B, 0x59, 0x20, 0x4C, 0x8B, 0x61, 0x28, 0x4C, 0x8B, 0x69, 0x30, 0x4C, + 0x8B, 0x71, 0x38, 0x4C, 0x8B, 0x79, 0x40, 0x48, 0x81, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83, + 0xE1, 0xF0, 0x0F, 0x29, 0x31, 0x0F, 0x29, 0x79, 0x10, 0x44, 0x0F, 0x29, 0x41, 0x20, 0x44, 0x0F, + 0x29, 0x49, 0x30, 0x44, 0x0F, 0x29, 0x51, 0x40, 0x44, 0x0F, 0x29, 0x59, 0x50, 0x44, 0x0F, 0x29, + 0x61, 0x60, 0x44, 0x0F, 0x29, 0x69, 0x70, 0x44, 0x0F, 0x29, 0xB1, 0x80, 0x00, 0x00, 0x00, 0x44, + 0x0F, 0x29, 0xB9, 0x90, 0x00, 0x00, 0x00, 0xFF, 0xE0, + }; + + #include + + void co_init() { + DWORD old_privileges; + VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges); + } +#else + //ABI: SystemV + static unsigned char co_swap_function[] = { + 0x48, 0x89, 0x26, 0x48, 0x8B, 0x27, 0x58, 0x48, 0x89, 0x6E, 0x08, 0x48, 0x89, 0x5E, 0x10, 0x4C, + 0x89, 0x66, 0x18, 0x4C, 0x89, 0x6E, 0x20, 0x4C, 0x89, 0x76, 0x28, 0x4C, 0x89, 0x7E, 0x30, 0x48, + 0x8B, 0x6F, 0x08, 0x48, 0x8B, 0x5F, 0x10, 0x4C, 0x8B, 0x67, 0x18, 0x4C, 0x8B, 0x6F, 0x20, 0x4C, + 0x8B, 0x77, 0x28, 0x4C, 0x8B, 0x7F, 0x30, 0xFF, 0xE0, + }; + + #include + #include + + void co_init() { + unsigned long long addr = (unsigned long long)co_swap_function; + unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE)); + unsigned long long size = (addr - base) + sizeof co_swap_function; + mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC); + } +#endif + +static void crash() { + assert(0); /* called only if cothread_t entrypoint returns */ +} + +cothread_t co_active() { + if(!co_active_handle) co_active_handle = &co_active_buffer; + return co_active_handle; +} + +cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { + cothread_t handle; + if(!co_swap) { + co_init(); + co_swap = (void (*)(cothread_t, cothread_t))co_swap_function; + } + if(!co_active_handle) co_active_handle = &co_active_buffer; + size += 512; /* allocate additional space for storage */ + size &= ~15; /* align stack to 16-byte boundary */ + + if(handle = (cothread_t)malloc(size)) { + long long *p = (long long*)((char*)handle + size); /* seek to top of stack */ + *--p = (long long)crash; /* crash if entrypoint returns */ + *--p = (long long)entrypoint; /* start of function */ + *(long long*)handle = (long long)p; /* stack pointer */ + } + + return handle; +} + +void co_delete(cothread_t handle) { + free(handle); +} + +void co_switch(cothread_t handle) { + register cothread_t co_previous_handle = co_active_handle; + co_swap(co_active_handle = handle, co_previous_handle); +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/fiber.c b/libco/fiber.c new file mode 100755 index 00000000..02ef5bc7 --- /dev/null +++ b/libco/fiber.c @@ -0,0 +1,51 @@ +/* + libco.win (2008-01-28) + authors: Nach, byuu + license: public domain +*/ + +#define LIBCO_C +#include "libco.h" +#define WINVER 0x0400 +#define _WIN32_WINNT 0x0400 +#define WIN32_LEAN_AND_MEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static thread_local cothread_t co_active_ = 0; + +static void __stdcall co_thunk(void *coentry) { + ((void (*)(void))coentry)(); +} + +cothread_t co_active() { + if(!co_active_) { + ConvertThreadToFiber(0); + co_active_ = GetCurrentFiber(); + } + return co_active_; +} + +cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) { + if(!co_active_) { + ConvertThreadToFiber(0); + co_active_ = GetCurrentFiber(); + } + return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry); +} + +void co_delete(cothread_t cothread) { + DeleteFiber(cothread); +} + +void co_switch(cothread_t cothread) { + co_active_ = cothread; + SwitchToFiber(cothread); +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/libco.c b/libco/libco.c new file mode 100755 index 00000000..55676263 --- /dev/null +++ b/libco/libco.c @@ -0,0 +1,23 @@ +/* + libco + auto-selection module + license: public domain +*/ + +#if defined(__GNUC__) && defined(__i386__) + #include "x86.c" +#elif defined(__GNUC__) && defined(__amd64__) + #include "amd64.c" +#elif defined(__GNUC__) && defined(_ARCH_PPC) + #include "ppc.c" +#elif defined(__GNUC__) + #include "sjlj.c" +#elif defined(_MSC_VER) && defined(_M_IX86) + #include "x86.c" +#elif defined(_MSC_VER) && defined(_M_AMD64) + #include "amd64.c" +#elif defined(_MSC_VER) + #include "fiber.c" +#else + #error "libco: unsupported processor, compiler or operating system" +#endif diff --git a/libco/libco.h b/libco/libco.h new file mode 100755 index 00000000..deb954fb --- /dev/null +++ b/libco/libco.h @@ -0,0 +1,34 @@ +/* + libco + version: 0.16 (2010-12-24) + license: public domain +*/ + +#ifndef LIBCO_H +#define LIBCO_H + +#ifdef LIBCO_C + #ifdef LIBCO_MP + #define thread_local __thread + #else + #define thread_local + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* cothread_t; + +cothread_t co_active(); +cothread_t co_create(unsigned int, void (*)(void)); +void co_delete(cothread_t); +void co_switch(cothread_t); + +#ifdef __cplusplus +} +#endif + +/* ifndef LIBCO_H */ +#endif diff --git a/libco/ppc.c b/libco/ppc.c new file mode 100755 index 00000000..a6028fdb --- /dev/null +++ b/libco/ppc.c @@ -0,0 +1,407 @@ +/* + libco.ppc (2010-10-17) + author: blargg + license: public domain +*/ + +/* PowerPC 32/64 using embedded or external asm, with optional +floating-point and AltiVec save/restore */ + +#define LIBCO_C +#include "libco.h" +#include +#include +#include + +#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM) + +#if LIBCO_MPROTECT + #include + #include +#endif + +/* State format (offsets in 32-bit words) + ++0 Pointer to swap code + Rest of function descriptor for entry function ++8 PC ++10 SP + Special regs + GPRs + FPRs + VRs + stack +*/ + +enum { state_size = 1024 }; +enum { above_stack = 2048 }; +enum { stack_align = 256 }; + +static thread_local cothread_t co_active_handle = 0; + +/**** Determine environment ****/ + +#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__) + +/* Whether function calls are indirect through a descriptor, +or are directly to function */ +#ifndef LIBCO_PPCDESC + #if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64) + #define LIBCO_PPCDESC 1 + #endif +#endif + +#ifdef LIBCO_PPC_ASM + + #ifdef __cplusplus + extern "C" + #endif + + /* Swap code is in ppc.S */ + void co_swap_asm( cothread_t, cothread_t ); + #define CO_SWAP_ASM( x, y ) co_swap_asm( x, y ) + +#else + +/* Swap code is here in array. Please leave dieassembly comments, +as they make it easy to see what it does, and reorder instructions +if one wants to see whether that improves performance. */ +static const uint32_t libco_ppc_code [] = { +#if LIBCO_PPC64 + 0x7d000026, /* mfcr r8 */ + 0xf8240028, /* std r1,40(r4) */ + 0x7d2802a6, /* mflr r9 */ + 0xf9c40048, /* std r14,72(r4) */ + 0xf9e40050, /* std r15,80(r4) */ + 0xfa040058, /* std r16,88(r4) */ + 0xfa240060, /* std r17,96(r4) */ + 0xfa440068, /* std r18,104(r4) */ + 0xfa640070, /* std r19,112(r4) */ + 0xfa840078, /* std r20,120(r4) */ + 0xfaa40080, /* std r21,128(r4) */ + 0xfac40088, /* std r22,136(r4) */ + 0xfae40090, /* std r23,144(r4) */ + 0xfb040098, /* std r24,152(r4) */ + 0xfb2400a0, /* std r25,160(r4) */ + 0xfb4400a8, /* std r26,168(r4) */ + 0xfb6400b0, /* std r27,176(r4) */ + 0xfb8400b8, /* std r28,184(r4) */ + 0xfba400c0, /* std r29,192(r4) */ + 0xfbc400c8, /* std r30,200(r4) */ + 0xfbe400d0, /* std r31,208(r4) */ + 0xf9240020, /* std r9,32(r4) */ + 0xe8e30020, /* ld r7,32(r3) */ + 0xe8230028, /* ld r1,40(r3) */ + 0x48000009, /* bl 1 */ + 0x7fe00008, /* trap */ + 0x91040030,/*1:stw r8,48(r4) */ + 0x80c30030, /* lwz r6,48(r3) */ + 0x7ce903a6, /* mtctr r7 */ + 0xe9c30048, /* ld r14,72(r3) */ + 0xe9e30050, /* ld r15,80(r3) */ + 0xea030058, /* ld r16,88(r3) */ + 0xea230060, /* ld r17,96(r3) */ + 0xea430068, /* ld r18,104(r3) */ + 0xea630070, /* ld r19,112(r3) */ + 0xea830078, /* ld r20,120(r3) */ + 0xeaa30080, /* ld r21,128(r3) */ + 0xeac30088, /* ld r22,136(r3) */ + 0xeae30090, /* ld r23,144(r3) */ + 0xeb030098, /* ld r24,152(r3) */ + 0xeb2300a0, /* ld r25,160(r3) */ + 0xeb4300a8, /* ld r26,168(r3) */ + 0xeb6300b0, /* ld r27,176(r3) */ + 0xeb8300b8, /* ld r28,184(r3) */ + 0xeba300c0, /* ld r29,192(r3) */ + 0xebc300c8, /* ld r30,200(r3) */ + 0xebe300d0, /* ld r31,208(r3) */ + 0x7ccff120, /* mtcr r6 */ +#else + 0x7d000026, /* mfcr r8 */ + 0x90240028, /* stw r1,40(r4) */ + 0x7d2802a6, /* mflr r9 */ + 0x91a4003c, /* stw r13,60(r4) */ + 0x91c40040, /* stw r14,64(r4) */ + 0x91e40044, /* stw r15,68(r4) */ + 0x92040048, /* stw r16,72(r4) */ + 0x9224004c, /* stw r17,76(r4) */ + 0x92440050, /* stw r18,80(r4) */ + 0x92640054, /* stw r19,84(r4) */ + 0x92840058, /* stw r20,88(r4) */ + 0x92a4005c, /* stw r21,92(r4) */ + 0x92c40060, /* stw r22,96(r4) */ + 0x92e40064, /* stw r23,100(r4) */ + 0x93040068, /* stw r24,104(r4) */ + 0x9324006c, /* stw r25,108(r4) */ + 0x93440070, /* stw r26,112(r4) */ + 0x93640074, /* stw r27,116(r4) */ + 0x93840078, /* stw r28,120(r4) */ + 0x93a4007c, /* stw r29,124(r4) */ + 0x93c40080, /* stw r30,128(r4) */ + 0x93e40084, /* stw r31,132(r4) */ + 0x91240020, /* stw r9,32(r4) */ + 0x80e30020, /* lwz r7,32(r3) */ + 0x80230028, /* lwz r1,40(r3) */ + 0x48000009, /* bl 1 */ + 0x7fe00008, /* trap */ + 0x91040030,/*1:stw r8,48(r4) */ + 0x80c30030, /* lwz r6,48(r3) */ + 0x7ce903a6, /* mtctr r7 */ + 0x81a3003c, /* lwz r13,60(r3) */ + 0x81c30040, /* lwz r14,64(r3) */ + 0x81e30044, /* lwz r15,68(r3) */ + 0x82030048, /* lwz r16,72(r3) */ + 0x8223004c, /* lwz r17,76(r3) */ + 0x82430050, /* lwz r18,80(r3) */ + 0x82630054, /* lwz r19,84(r3) */ + 0x82830058, /* lwz r20,88(r3) */ + 0x82a3005c, /* lwz r21,92(r3) */ + 0x82c30060, /* lwz r22,96(r3) */ + 0x82e30064, /* lwz r23,100(r3) */ + 0x83030068, /* lwz r24,104(r3) */ + 0x8323006c, /* lwz r25,108(r3) */ + 0x83430070, /* lwz r26,112(r3) */ + 0x83630074, /* lwz r27,116(r3) */ + 0x83830078, /* lwz r28,120(r3) */ + 0x83a3007c, /* lwz r29,124(r3) */ + 0x83c30080, /* lwz r30,128(r3) */ + 0x83e30084, /* lwz r31,132(r3) */ + 0x7ccff120, /* mtcr r6 */ +#endif + +#ifndef LIBCO_PPC_NOFP + 0xd9c400e0, /* stfd f14,224(r4) */ + 0xd9e400e8, /* stfd f15,232(r4) */ + 0xda0400f0, /* stfd f16,240(r4) */ + 0xda2400f8, /* stfd f17,248(r4) */ + 0xda440100, /* stfd f18,256(r4) */ + 0xda640108, /* stfd f19,264(r4) */ + 0xda840110, /* stfd f20,272(r4) */ + 0xdaa40118, /* stfd f21,280(r4) */ + 0xdac40120, /* stfd f22,288(r4) */ + 0xdae40128, /* stfd f23,296(r4) */ + 0xdb040130, /* stfd f24,304(r4) */ + 0xdb240138, /* stfd f25,312(r4) */ + 0xdb440140, /* stfd f26,320(r4) */ + 0xdb640148, /* stfd f27,328(r4) */ + 0xdb840150, /* stfd f28,336(r4) */ + 0xdba40158, /* stfd f29,344(r4) */ + 0xdbc40160, /* stfd f30,352(r4) */ + 0xdbe40168, /* stfd f31,360(r4) */ + 0xc9c300e0, /* lfd f14,224(r3) */ + 0xc9e300e8, /* lfd f15,232(r3) */ + 0xca0300f0, /* lfd f16,240(r3) */ + 0xca2300f8, /* lfd f17,248(r3) */ + 0xca430100, /* lfd f18,256(r3) */ + 0xca630108, /* lfd f19,264(r3) */ + 0xca830110, /* lfd f20,272(r3) */ + 0xcaa30118, /* lfd f21,280(r3) */ + 0xcac30120, /* lfd f22,288(r3) */ + 0xcae30128, /* lfd f23,296(r3) */ + 0xcb030130, /* lfd f24,304(r3) */ + 0xcb230138, /* lfd f25,312(r3) */ + 0xcb430140, /* lfd f26,320(r3) */ + 0xcb630148, /* lfd f27,328(r3) */ + 0xcb830150, /* lfd f28,336(r3) */ + 0xcba30158, /* lfd f29,344(r3) */ + 0xcbc30160, /* lfd f30,352(r3) */ + 0xcbe30168, /* lfd f31,360(r3) */ +#endif + +#ifdef __ALTIVEC__ + 0x7ca042a6, /* mfvrsave r5 */ + 0x39040180, /* addi r8,r4,384 */ + 0x39240190, /* addi r9,r4,400 */ + 0x70a00fff, /* andi. r0,r5,4095 */ + 0x90a40034, /* stw r5,52(r4) */ + 0x4182005c, /* beq- 2 */ + 0x7e8041ce, /* stvx v20,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7ea049ce, /* stvx v21,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7ec041ce, /* stvx v22,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7ee049ce, /* stvx v23,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7f0041ce, /* stvx v24,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7f2049ce, /* stvx v25,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7f4041ce, /* stvx v26,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7f6049ce, /* stvx v27,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7f8041ce, /* stvx v28,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7fa049ce, /* stvx v29,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7fc041ce, /* stvx v30,r0,r8 */ + 0x7fe049ce, /* stvx v31,r0,r9 */ + 0x80a30034,/*2:lwz r5,52(r3) */ + 0x39030180, /* addi r8,r3,384 */ + 0x39230190, /* addi r9,r3,400 */ + 0x70a00fff, /* andi. r0,r5,4095 */ + 0x7ca043a6, /* mtvrsave r5 */ + 0x4d820420, /* beqctr */ + 0x7e8040ce, /* lvx v20,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7ea048ce, /* lvx v21,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7ec040ce, /* lvx v22,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7ee048ce, /* lvx v23,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7f0040ce, /* lvx v24,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7f2048ce, /* lvx v25,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7f4040ce, /* lvx v26,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7f6048ce, /* lvx v27,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7f8040ce, /* lvx v28,r0,r8 */ + 0x39080020, /* addi r8,r8,32 */ + 0x7fa048ce, /* lvx v29,r0,r9 */ + 0x39290020, /* addi r9,r9,32 */ + 0x7fc040ce, /* lvx v30,r0,r8 */ + 0x7fe048ce, /* lvx v31,r0,r9 */ +#endif + + 0x4e800420, /* bctr */ +}; + + #if LIBCO_PPCDESC + /* Function call goes through indirect descriptor */ + #define CO_SWAP_ASM( x, y ) \ + ((void (*)( cothread_t, cothread_t )) (uintptr_t) x)( x, y ) + #else + /* Function call goes directly to code */ + #define CO_SWAP_ASM( x, y ) \ + ((void (*)( cothread_t, cothread_t )) (uintptr_t) libco_ppc_code)( x, y ) + #endif + +#endif + +static uint32_t* co_create_( unsigned size, uintptr_t entry ) +{ + uint32_t* t = (uint32_t*) malloc( size ); + + (void) entry; + + #if LIBCO_PPCDESC + if ( t ) + { + /* Copy entry's descriptor */ + memcpy( t, (void*) entry, sizeof (void*) * 3 ); + + /* Set function pointer to swap routine */ + #ifdef LIBCO_PPC_ASM + *(const void**) t = *(void**) &co_swap_asm; + #else + *(const void**) t = libco_ppc_code; + #endif + } + #endif + + return t; +} + +cothread_t co_create( unsigned int size, void (*entry_)( void ) ) +{ + uintptr_t entry = (uintptr_t) entry_; + uint32_t* t = NULL; + + /* Be sure main thread was successfully allocated */ + if ( co_active() ) + { + size += state_size + above_stack + stack_align; + t = co_create_( size, entry ); + } + + if ( t ) + { + uintptr_t sp; + int shift; + + /* Save current registers into new thread, so that any special ones will + have proper values when thread is begun */ + CO_SWAP_ASM( t, t ); + + #if LIBCO_PPCDESC + /* Get real address */ + entry = (uintptr_t) *(void**) entry; + #endif + + /* Put stack near end of block, and align */ + sp = (uintptr_t) t + size - above_stack; + sp -= sp % stack_align; + + /* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we + save and restore them as 64 bits, regardless of the size the ABI + uses. So, we manually write pointers at the proper size. We always + save and restore at the same address, and since PPC is big-endian, + we must put the low byte first on PPC32. */ + + /* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts + and don't have to care how many bits uintptr_t is. */ + #if LIBCO_PPC64 + shift = 16; + #else + shift = 0; + #endif + + /* Set up so entry will be called on next swap */ + t [8] = (uint32_t) (entry >> shift >> shift); + t [9] = (uint32_t) entry; + + t [10] = (uint32_t) (sp >> shift >> shift); + t [11] = (uint32_t) sp; + } + + return t; +} + +void co_delete( cothread_t t ) +{ + free( t ); +} + +static void co_init_( void ) +{ + #if LIBCO_MPROTECT + /* TODO: pre- and post-pad PPC code so that this doesn't make other + data executable and writable */ + long page_size = sysconf( _SC_PAGESIZE ); + if ( page_size > 0 ) + { + uintptr_t align = page_size; + uintptr_t begin = (uintptr_t) libco_ppc_code; + uintptr_t end = begin + sizeof libco_ppc_code; + + /* Align beginning and end */ + end += align - 1; + end -= end % align; + begin -= begin % align; + + mprotect( (void*) begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC ); + } + #endif + + co_active_handle = co_create_( state_size, (uintptr_t) &co_switch ); +} + +cothread_t co_active() +{ + if ( !co_active_handle ) + co_init_(); + + return co_active_handle; +} + +void co_switch( cothread_t t ) +{ + cothread_t old = co_active_handle; + co_active_handle = t; + + CO_SWAP_ASM( t, old ); +} diff --git a/libco/sjlj.c b/libco/sjlj.c new file mode 100755 index 00000000..8b72b614 --- /dev/null +++ b/libco/sjlj.c @@ -0,0 +1,102 @@ +/* + libco.sjlj (2008-01-28) + author: Nach + license: public domain +*/ + +/* + * Note this was designed for UNIX systems. Based on ideas expressed in a paper + * by Ralf Engelschall. + * For SJLJ on other systems, one would want to rewrite springboard() and + * co_create() and hack the jmb_buf stack pointer. + */ + +#define LIBCO_C +#include "libco.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + sigjmp_buf context; + void (*coentry)(void); + void *stack; +} cothread_struct; + +static thread_local cothread_struct co_primary; +static thread_local cothread_struct *creating, *co_running = 0; + +static void springboard(int ignored) { + if(sigsetjmp(creating->context, 0)) { + co_running->coentry(); + } +} + +cothread_t co_active() { + if(!co_running) co_running = &co_primary; + return (cothread_t)co_running; +} + +cothread_t co_create(unsigned int size, void (*coentry)(void)) { + if(!co_running) co_running = &co_primary; + + cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct)); + if(thread) { + struct sigaction handler; + struct sigaction old_handler; + + stack_t stack; + stack_t old_stack; + + thread->coentry = thread->stack = 0; + + stack.ss_flags = 0; + stack.ss_size = size; + thread->stack = stack.ss_sp = malloc(size); + if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) { + handler.sa_handler = springboard; + handler.sa_flags = SA_ONSTACK; + sigemptyset(&handler.sa_mask); + creating = thread; + + if(!sigaction(SIGUSR1, &handler, &old_handler)) { + if(!raise(SIGUSR1)) { + thread->coentry = coentry; + } + sigaltstack(&old_stack, 0); + sigaction(SIGUSR1, &old_handler, 0); + } + } + + if(thread->coentry != coentry) { + co_delete(thread); + thread = 0; + } + } + + return (cothread_t)thread; +} + +void co_delete(cothread_t cothread) { + if(cothread) { + if(((cothread_struct*)cothread)->stack) { + free(((cothread_struct*)cothread)->stack); + } + free(cothread); + } +} + +void co_switch(cothread_t cothread) { + if(!sigsetjmp(co_running->context, 0)) { + co_running = (cothread_struct*)cothread; + siglongjmp(co_running->context, 1); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/ucontext.c b/libco/ucontext.c new file mode 100755 index 00000000..17472f6b --- /dev/null +++ b/libco/ucontext.c @@ -0,0 +1,67 @@ +/* + libco.ucontext (2008-01-28) + author: Nach + license: public domain +*/ + +/* + * WARNING: the overhead of POSIX ucontext is very high, + * assembly versions of libco or libco_sjlj should be much faster + * + * This library only exists for two reasons: + * 1 - as an initial test for the viability of a ucontext implementation + * 2 - to demonstrate the power and speed of libco over existing implementations, + * such as pth (which defaults to wrapping ucontext on unix targets) + * + * Use this library only as a *last resort* + */ + +#define LIBCO_C +#include "libco.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static thread_local ucontext_t co_primary; +static thread_local ucontext_t *co_running = 0; + +cothread_t co_active() { + if(!co_running) co_running = &co_primary; + return (cothread_t)co_running; +} + +cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) { + if(!co_running) co_running = &co_primary; + ucontext_t *thread = (ucontext_t*)malloc(sizeof(ucontext_t)); + if(thread) { + if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize))) { + thread->uc_link = co_running; + thread->uc_stack.ss_size = heapsize; + makecontext(thread, coentry, 0); + } else { + co_delete((cothread_t)thread); + thread = 0; + } + } + return (cothread_t)thread; +} + +void co_delete(cothread_t cothread) { + if(cothread) { + if(((ucontext_t*)cothread)->uc_stack.ss_sp) { free(((ucontext_t*)cothread)->uc_stack.ss_sp); } + free(cothread); + } +} + +void co_switch(cothread_t cothread) { + ucontext_t *old_thread = co_running; + co_running = (ucontext_t*)cothread; + swapcontext(old_thread, co_running); +} + +#ifdef __cplusplus +} +#endif diff --git a/libco/x86.c b/libco/x86.c new file mode 100755 index 00000000..d8f820b0 --- /dev/null +++ b/libco/x86.c @@ -0,0 +1,93 @@ +/* + libco.x86 (2009-10-12) + author: byuu + license: public domain +*/ + +#define LIBCO_C +#include "libco.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) + #define fastcall __fastcall +#elif defined(__GNUC__) + #define fastcall __attribute__((fastcall)) +#else + #error "libco: please define fastcall macro" +#endif + +static thread_local long co_active_buffer[64]; +static thread_local cothread_t co_active_handle = 0; +static void (fastcall *co_swap)(cothread_t, cothread_t) = 0; + +//ABI: fastcall +static unsigned char co_swap_function[] = { + 0x89, 0x22, 0x8B, 0x21, 0x58, 0x89, 0x6A, 0x04, 0x89, 0x72, 0x08, 0x89, 0x7A, 0x0C, 0x89, 0x5A, + 0x10, 0x8B, 0x69, 0x04, 0x8B, 0x71, 0x08, 0x8B, 0x79, 0x0C, 0x8B, 0x59, 0x10, 0xFF, 0xE0, +}; + +#ifdef _WIN32 + #include + + void co_init() { + DWORD old_privileges; + VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges); + } +#else + #include + #include + + void co_init() { + unsigned long addr = (unsigned long)co_swap_function; + unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE)); + unsigned long size = (addr - base) + sizeof co_swap_function; + mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC); + } +#endif + +static void crash() { + assert(0); /* called only if cothread_t entrypoint returns */ +} + +cothread_t co_active() { + if(!co_active_handle) co_active_handle = &co_active_buffer; + return co_active_handle; +} + +cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { + cothread_t handle; + if(!co_swap) { + co_init(); + co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function; + } + if(!co_active_handle) co_active_handle = &co_active_buffer; + size += 256; /* allocate additional space for storage */ + size &= ~15; /* align stack to 16-byte boundary */ + + if(handle = (cothread_t)malloc(size)) { + long *p = (long*)((char*)handle + size); /* seek to top of stack */ + *--p = (long)crash; /* crash if entrypoint returns */ + *--p = (long)entrypoint; /* start of function */ + *(long*)handle = (long)p; /* stack pointer */ + } + + return handle; +} + +void co_delete(cothread_t handle) { + free(handle); +} + +void co_switch(cothread_t handle) { + register cothread_t co_previous_handle = co_active_handle; + co_swap(co_active_handle = handle, co_previous_handle); +} + +#ifdef __cplusplus +} +#endif diff --git a/nall/Makefile b/nall/Makefile new file mode 100755 index 00000000..a542beeb --- /dev/null +++ b/nall/Makefile @@ -0,0 +1,112 @@ +# Makefile +# author: byuu +# license: public domain + +[A-Z] = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +[a-z] = a b c d e f g h i j k l m n o p q r s t u v w x y z +[0-9] = 0 1 2 3 4 5 6 7 8 9 +[markup] = ` ~ ! @ \# $$ % ^ & * ( ) - _ = + [ { ] } \ | ; : ' " , < . > / ? +[all] = $([A-Z]) $([a-z]) $([0-9]) $([markup]) +[space] := +[space] += + +##### +# platform detection +##### + +ifeq ($(platform),) + uname := $(shell uname -a) + ifeq ($(uname),) + platform := win + delete = del $(subst /,\,$1) + else ifneq ($(findstring CYGWIN,$(uname)),) + platform := win + delete = del $(subst /,\,$1) + else ifneq ($(findstring Darwin,$(uname)),) + platform := osx + delete = rm -f $1 + else + platform := x + delete = rm -f $1 + endif +endif + +ifeq ($(compiler),) + ifeq ($(platform),win) + compiler := gcc + else ifeq ($(platform),osx) + compiler := gcc-mp-4.6 + else + compiler := gcc-4.6 + endif +endif + +ifeq ($(prefix),) + prefix := /usr/local +endif + +##### +# function rwildcard(directory, pattern) +##### +rwildcard = \ + $(strip \ + $(filter $(if $2,$2,%), \ + $(foreach f, \ + $(wildcard $1*), \ + $(eval t = $(call rwildcard,$f/)) \ + $(if $t,$t,$f) \ + ) \ + ) \ + ) + +##### +# function strtr(source, from, to) +##### +strtr = \ + $(eval __temp := $1) \ + $(strip \ + $(foreach c, \ + $(join $(addsuffix :,$2),$3), \ + $(eval __temp := \ + $(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)),$(__temp)) \ + ) \ + ) \ + $(__temp) \ + ) + +##### +# function strupper(source) +##### +strupper = $(call strtr,$1,$([a-z]),$([A-Z])) + +##### +# function strlower(source) +##### +strlower = $(call strtr,$1,$([A-Z]),$([a-z])) + +##### +# function strlen(source) +##### +strlen = \ + $(eval __temp := $(subst $([space]),_,$1)) \ + $(words \ + $(strip \ + $(foreach c, \ + $([all]), \ + $(eval __temp := \ + $(subst $c,$c ,$(__temp)) \ + ) \ + ) \ + $(__temp) \ + ) \ + ) + +##### +# function streq(source) +##### +streq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),,1) + +##### +# function strne(source) +##### +strne = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),1,) diff --git a/nall/algorithm.hpp b/nall/algorithm.hpp new file mode 100755 index 00000000..037f0bb7 --- /dev/null +++ b/nall/algorithm.hpp @@ -0,0 +1,17 @@ +#ifndef NALL_ALGORITHM_HPP +#define NALL_ALGORITHM_HPP + +#undef min +#undef max + +namespace nall { + template T min(const T &t, const U &u) { + return t < u ? t : u; + } + + template T max(const T &t, const U &u) { + return t > u ? t : u; + } +} + +#endif diff --git a/nall/any.hpp b/nall/any.hpp new file mode 100755 index 00000000..b31cff3c --- /dev/null +++ b/nall/any.hpp @@ -0,0 +1,74 @@ +#ifndef NALL_ANY_HPP +#define NALL_ANY_HPP + +#include +#include +#include + +namespace nall { + class any { + public: + bool empty() const { return container; } + const std::type_info& type() const { return container ? container->type() : typeid(void); } + + template any& operator=(const T& value_) { + typedef typename static_if< + std::is_array::value, + typename std::remove_extent::type>::type*, + T + >::type auto_t; + + if(type() == typeid(auto_t)) { + static_cast*>(container)->value = (auto_t)value_; + } else { + if(container) delete container; + container = new holder((auto_t)value_); + } + + return *this; + } + + any() : container(0) {} + template any(const T& value_) : container(0) { operator=(value_); } + + private: + struct placeholder { + virtual const std::type_info& type() const = 0; + } *container; + + template struct holder : placeholder { + T value; + const std::type_info& type() const { return typeid(T); } + holder(const T& value_) : value(value_) {} + }; + + template friend T any_cast(any&); + template friend T any_cast(const any&); + template friend T* any_cast(any*); + template friend const T* any_cast(const any*); + }; + + template T any_cast(any &value) { + typedef typename std::remove_reference::type nonref; + if(value.type() != typeid(nonref)) throw; + return static_cast*>(value.container)->value; + } + + template T any_cast(const any &value) { + typedef const typename std::remove_reference::type nonref; + if(value.type() != typeid(nonref)) throw; + return static_cast*>(value.container)->value; + } + + template T* any_cast(any *value) { + if(!value || value->type() != typeid(T)) return 0; + return &static_cast*>(value->container)->value; + } + + template const T* any_cast(const any *value) { + if(!value || value->type() != typeid(T)) return 0; + return &static_cast*>(value->container)->value; + } +} + +#endif diff --git a/nall/array.hpp b/nall/array.hpp new file mode 100755 index 00000000..4847a297 --- /dev/null +++ b/nall/array.hpp @@ -0,0 +1,141 @@ +#ifndef NALL_ARRAY_HPP +#define NALL_ARRAY_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall { + //dynamic vector array + //neither constructor nor destructor is ever invoked; + //thus, this should only be used for POD objects. + template class array { + protected: + T *pool; + unsigned poolsize, buffersize; + + public: + unsigned size() const { return buffersize; } + unsigned capacity() const { return poolsize; } + + void reset() { + if(pool) free(pool); + pool = nullptr; + poolsize = 0; + buffersize = 0; + } + + void reserve(unsigned newsize) { + if(newsize == poolsize) return; + + pool = (T*)realloc(pool, newsize * sizeof(T)); + poolsize = newsize; + buffersize = min(buffersize, newsize); + } + + void resize(unsigned newsize) { + if(newsize > poolsize) reserve(bit::round(newsize)); //round reserve size up to power of 2 + buffersize = newsize; + } + + T* get(unsigned minsize = 0) { + if(minsize > buffersize) resize(minsize); + if(minsize > buffersize) throw "array[] out of bounds"; + return pool; + } + + void append(const T data) { + operator[](buffersize) = data; + } + + void append(const T data[], unsigned length) { + for(unsigned n = 0; n < length; n++) operator[](buffersize) = data[n]; + } + + void remove() { + if(size > 0) resize(size - 1); //remove last element only + } + + void remove(unsigned index, unsigned count = 1) { + for(unsigned i = index; count + i < buffersize; i++) { + pool[i] = pool[count + i]; + } + if(count + index >= buffersize) resize(index); //every element >= index was removed + else resize(buffersize - count); + } + + optional find(const T data) { + for(unsigned i = 0; i < size(); i++) if(pool[i] == data) return { true, i }; + return { false, 0 }; + } + + void clear() { + memset(pool, 0, buffersize * sizeof(T)); + } + + array() : pool(nullptr), poolsize(0), buffersize(0) { + } + + array(std::initializer_list list) : pool(nullptr), poolsize(0), buffersize(0) { + for(const T *p = list.begin(); p != list.end(); ++p) append(*p); + } + + ~array() { + reset(); + } + + //copy + array& operator=(const array &source) { + if(pool) free(pool); + buffersize = source.buffersize; + poolsize = source.poolsize; + pool = (T*)malloc(sizeof(T) * poolsize); //allocate entire pool size, + memcpy(pool, source.pool, sizeof(T) * buffersize); //... but only copy used pool objects + return *this; + } + + array(const array &source) : pool(nullptr), poolsize(0), buffersize(0) { + operator=(source); + } + + //move + array& operator=(array &&source) { + if(pool) free(pool); + pool = source.pool; + poolsize = source.poolsize; + buffersize = source.buffersize; + source.pool = nullptr; + source.reset(); + return *this; + } + + array(array &&source) : pool(nullptr), poolsize(0), buffersize(0) { + operator=(std::move(source)); + } + + //index + inline T& operator[](unsigned index) { + if(index >= buffersize) resize(index + 1); + if(index >= buffersize) throw "array[] out of bounds"; + return pool[index]; + } + + inline const T& operator[](unsigned index) const { + if(index >= buffersize) throw "array[] out of bounds"; + return pool[index]; + } + + //iteration + T* begin() { return &pool[0]; } + T* end() { return &pool[buffersize]; } + const T* begin() const { return &pool[0]; } + const T* end() const { return &pool[buffersize]; } + }; +} + +#endif diff --git a/nall/atoi.hpp b/nall/atoi.hpp new file mode 100755 index 00000000..cec3e72d --- /dev/null +++ b/nall/atoi.hpp @@ -0,0 +1,88 @@ +#ifndef NALL_ATOI_HPP +#define NALL_ATOI_HPP + +namespace nall { + +//note: this header is intended to form the base for user-defined literals; +//once they are supported by GCC. eg: +//unsigned operator "" b(const char *s) { return binary(s); } +//-> signed data = 1001b; +//(0b1001 is nicer, but is not part of the C++ standard) + +constexpr inline uintmax_t binary_(const char *s, uintmax_t sum = 0) { + return ( + *s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') : + sum + ); +} + +constexpr inline uintmax_t octal_(const char *s, uintmax_t sum = 0) { + return ( + *s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') : + sum + ); +} + +constexpr inline uintmax_t decimal_(const char *s, uintmax_t sum = 0) { + return ( + *s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') : + sum + ); +} + +constexpr inline uintmax_t hex_(const char *s, uintmax_t sum = 0) { + return ( + *s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) : + *s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) : + *s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') : + sum + ); +} + +// + +constexpr inline uintmax_t binary(const char *s) { + return ( + *s == '0' && *(s + 1) == 'B' ? binary_(s + 2) : + *s == '0' && *(s + 1) == 'b' ? binary_(s + 2) : + *s == '%' ? binary_(s + 1) : + binary_(s) + ); +} + +constexpr inline uintmax_t octal(const char *s) { + return ( + octal_(s) + ); +} + +constexpr inline intmax_t integer(const char *s) { + return ( + *s == '+' ? +decimal_(s + 1) : + *s == '-' ? -decimal_(s + 1) : + decimal_(s) + ); +} + +constexpr inline uintmax_t decimal(const char *s) { + return ( + decimal_(s) + ); +} + +constexpr inline uintmax_t hex(const char *s) { + return ( + *s == '0' && *(s + 1) == 'X' ? hex_(s + 2) : + *s == '0' && *(s + 1) == 'x' ? hex_(s + 2) : + *s == '$' ? hex_(s + 1) : + hex_(s) + ); +} + +inline double fp(const char *s) { + return atof(s); +} + +} + +#endif diff --git a/nall/base64.hpp b/nall/base64.hpp new file mode 100755 index 00000000..a0afd8b1 --- /dev/null +++ b/nall/base64.hpp @@ -0,0 +1,90 @@ +#ifndef NALL_BASE64_HPP +#define NALL_BASE64_HPP + +#include +#include + +namespace nall { + struct base64 { + static bool encode(char *&output, const uint8_t* input, unsigned inlength) { + output = new char[inlength * 8 / 6 + 6](); + + unsigned i = 0, o = 0; + while(i < inlength) { + switch(i % 3) { + case 0: { + output[o++] = enc(input[i] >> 2); + output[o] = enc((input[i] & 3) << 4); + } break; + + case 1: { + uint8_t prev = dec(output[o]); + output[o++] = enc(prev + (input[i] >> 4)); + output[o] = enc((input[i] & 15) << 2); + } break; + + case 2: { + uint8_t prev = dec(output[o]); + output[o++] = enc(prev + (input[i] >> 6)); + output[o++] = enc(input[i] & 63); + } break; + } + + i++; + } + + return true; + } + + static bool decode(uint8_t *&output, unsigned &outlength, const char *input) { + unsigned inlength = strlen(input), infix = 0; + output = new uint8_t[inlength](); + + unsigned i = 0, o = 0; + while(i < inlength) { + uint8_t x = dec(input[i]); + + switch(i++ & 3) { + case 0: { + output[o] = x << 2; + } break; + + case 1: { + output[o++] |= x >> 4; + output[o] = (x & 15) << 4; + } break; + + case 2: { + output[o++] |= x >> 2; + output[o] = (x & 3) << 6; + } break; + + case 3: { + output[o++] |= x; + } break; + } + } + + outlength = o; + return true; + } + + private: + static char enc(uint8_t n) { + //base64 for URL encodings + static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + return lookup_table[n & 63]; + } + + static uint8_t dec(char n) { + if(n >= 'A' && n <= 'Z') return n - 'A'; + if(n >= 'a' && n <= 'z') return n - 'a' + 26; + if(n >= '0' && n <= '9') return n - '0' + 52; + if(n == '-') return 62; + if(n == '_') return 63; + return 0; + } + }; +} + +#endif diff --git a/nall/bit.hpp b/nall/bit.hpp new file mode 100755 index 00000000..67a35ad6 --- /dev/null +++ b/nall/bit.hpp @@ -0,0 +1,51 @@ +#ifndef NALL_BIT_HPP +#define NALL_BIT_HPP + +namespace nall { + template constexpr inline unsigned uclamp(const unsigned x) { + enum { y = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) }; + return y + ((x - y) & -(x < y)); //min(x, y); + } + + template constexpr inline unsigned uclip(const unsigned x) { + enum { m = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) }; + return (x & m); + } + + template constexpr inline signed sclamp(const signed x) { + enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 }; + return (x > m) ? m : (x < -b) ? -b : x; + } + + template constexpr inline signed sclip(const signed x) { + enum { b = 1U << (bits - 1), m = (1U << bits) - 1 }; + return ((x & m) ^ b) - b; + } + + namespace bit { + //lowest(0b1110) == 0b0010 + template constexpr inline T lowest(const T x) { + return x & -x; + } + + //clear_lowest(0b1110) == 0b1100 + template constexpr inline T clear_lowest(const T x) { + return x & (x - 1); + } + + //set_lowest(0b0101) == 0b0111 + template constexpr inline T set_lowest(const T x) { + return x | (x + 1); + } + + //round up to next highest single bit: + //round(15) == 16, round(16) == 16, round(17) == 32 + inline unsigned round(unsigned x) { + if((x & (x - 1)) == 0) return x; + while(x & (x - 1)) x &= x - 1; + return x << 1; + } + } +} + +#endif diff --git a/nall/bmp.hpp b/nall/bmp.hpp new file mode 100755 index 00000000..33cdf4dc --- /dev/null +++ b/nall/bmp.hpp @@ -0,0 +1,101 @@ +#ifndef NALL_BMP_HPP +#define NALL_BMP_HPP + +#include + +//BMP reader / writer +//author: byuu +//note: only 24-bit RGB and 32-bit ARGB uncompressed images supported + +namespace nall { + +struct bmp { + inline static bool read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height); + inline static bool write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha = false); +}; + +bool bmp::read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height) { + file fp; + if(fp.open(filename, file::mode::read) == false) return false; + if(fp.size() < 0x36) return false; + + if(fp.readm(2) != 0x424d) return false; + fp.seek(0x000a); + unsigned offset = fp.readl(4); + unsigned dibsize = fp.readl(4); + if(dibsize != 40) return false; + signed headerWidth = fp.readl(4); + if(headerWidth < 0) return false; + signed headerHeight = fp.readl(4); + fp.readl(2); + unsigned bitsPerPixel = fp.readl(2); + if(bitsPerPixel != 24 && bitsPerPixel != 32) return false; + unsigned compression = fp.readl(4); + if(compression != 0) return false; + fp.seek(offset); + + bool noFlip = headerHeight < 0; + width = headerWidth, height = abs(headerHeight); + data = new uint32_t[width * height]; + + unsigned bytesPerPixel = bitsPerPixel / 8; + unsigned alignedWidth = width * bytesPerPixel; + unsigned paddingLength = 0; + while(alignedWidth % 4) alignedWidth++, paddingLength++; + + for(unsigned y = 0; y < height; y++) { + uint32_t *p = noFlip ? data + y * width : data + (height - 1 - y) * width; + for(unsigned x = 0; x < width; x++, p++) { + *p = fp.readl(bytesPerPixel); + if(bytesPerPixel == 3) *p |= 255 << 24; + } + if(paddingLength) fp.readl(paddingLength); + } + + fp.close(); + return true; +} + +bool bmp::write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha) { + file fp; + if(fp.open(filename, file::mode::write) == false) return false; + + unsigned bitsPerPixel = alpha ? 32 : 24; + unsigned bytesPerPixel = bitsPerPixel / 8; + unsigned alignedWidth = width * bytesPerPixel; + unsigned paddingLength = 0; + unsigned imageSize = alignedWidth * height; + unsigned fileSize = 0x36 + imageSize; + while(alignedWidth % 4) alignedWidth++, paddingLength++; + + fp.writem(0x424d, 2); //signature + fp.writel(fileSize, 4); //file size + fp.writel(0, 2); //reserved + fp.writel(0, 2); //reserved + fp.writel(0x36, 4); //offset + + fp.writel(40, 4); //DIB size + fp.writel(width, 4); //width + fp.writel(-height, 4); //height + fp.writel(1, 2); //color planes + fp.writel(bitsPerPixel, 2); //bits per pixel + fp.writel(0, 4); //compression method (BI_RGB) + fp.writel(imageSize, 4); //image data size + fp.writel(3780, 4); //horizontal resolution + fp.writel(3780, 4); //vertical resolution + fp.writel(0, 4); //palette size + fp.writel(0, 4); //important color count + + for(unsigned y = 0; y < height; y++) { + const uint32_t *p = (const uint32_t*)((const uint8_t*)data + y * pitch); + for(unsigned x = 0; x < width; x++) fp.writel(*p++, bytesPerPixel); + if(paddingLength) fp.writel(0, paddingLength); + } + + fp.close(); + return true; +} + +} + +#endif diff --git a/nall/bps/delta.hpp b/nall/bps/delta.hpp new file mode 100755 index 00000000..6cee56a3 --- /dev/null +++ b/nall/bps/delta.hpp @@ -0,0 +1,214 @@ +#ifndef NALL_BPS_DELTA_HPP +#define NALL_BPS_DELTA_HPP + +#include +#include +#include +#include +#include + +namespace nall { + +struct bpsdelta { + inline void source(const uint8_t *data, unsigned size); + inline void target(const uint8_t *data, unsigned size); + + inline bool source(const string &filename); + inline bool target(const string &filename); + inline bool create(const string &filename, const string &metadata = ""); + +protected: + enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy }; + enum : unsigned { Granularity = 1 }; + + struct Node { + unsigned offset; + Node *next; + inline Node() : offset(0), next(nullptr) {} + inline ~Node() { if(next) delete next; } + }; + + filemap sourceFile; + const uint8_t *sourceData; + unsigned sourceSize; + + filemap targetFile; + const uint8_t *targetData; + unsigned targetSize; +}; + +void bpsdelta::source(const uint8_t *data, unsigned size) { + sourceData = data; + sourceSize = size; +} + +void bpsdelta::target(const uint8_t *data, unsigned size) { + targetData = data; + targetSize = size; +} + +bool bpsdelta::source(const string &filename) { + if(sourceFile.open(filename, filemap::mode::read) == false) return false; + source(sourceFile.data(), sourceFile.size()); + return true; +} + +bool bpsdelta::target(const string &filename) { + if(targetFile.open(filename, filemap::mode::read) == false) return false; + target(targetFile.data(), targetFile.size()); + return true; +} + +bool bpsdelta::create(const string &filename, const string &metadata) { + file modifyFile; + if(modifyFile.open(filename, file::mode::write) == false) return false; + + uint32_t sourceChecksum = ~0, modifyChecksum = ~0; + unsigned sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0; + + auto write = [&](uint8_t data) { + modifyFile.write(data); + modifyChecksum = crc32_adjust(modifyChecksum, data); + }; + + auto encode = [&](uint64_t data) { + while(true) { + uint64_t x = data & 0x7f; + data >>= 7; + if(data == 0) { + write(0x80 | x); + break; + } + write(x); + data--; + } + }; + + write('B'); + write('P'); + write('S'); + write('1'); + + encode(sourceSize); + encode(targetSize); + + unsigned markupSize = metadata.length(); + encode(markupSize); + for(unsigned n = 0; n < markupSize; n++) write(metadata[n]); + + Node *sourceTree[65536], *targetTree[65536]; + for(unsigned n = 0; n < 65536; n++) sourceTree[n] = 0, targetTree[n] = 0; + + //source tree creation + for(unsigned offset = 0; offset < sourceSize; offset++) { + uint16_t symbol = sourceData[offset + 0]; + sourceChecksum = crc32_adjust(sourceChecksum, symbol); + if(offset < sourceSize - 1) symbol |= sourceData[offset + 1] << 8; + Node *node = new Node; + node->offset = offset; + node->next = sourceTree[symbol]; + sourceTree[symbol] = node; + } + + unsigned targetReadLength = 0; + + auto targetReadFlush = [&]() { + if(targetReadLength) { + encode(TargetRead | ((targetReadLength - 1) << 2)); + unsigned offset = outputOffset - targetReadLength; + while(targetReadLength) write(targetData[offset++]), targetReadLength--; + } + }; + + while(outputOffset < targetSize) { + unsigned maxLength = 0, maxOffset = 0, mode = TargetRead; + + uint16_t symbol = targetData[outputOffset + 0]; + if(outputOffset < targetSize - 1) symbol |= targetData[outputOffset + 1] << 8; + + { //source read + unsigned length = 0, offset = outputOffset; + while(offset < sourceSize && offset < targetSize && sourceData[offset] == targetData[offset]) { + length++; + offset++; + } + if(length > maxLength) maxLength = length, mode = SourceRead; + } + + { //source copy + Node *node = sourceTree[symbol]; + while(node) { + unsigned length = 0, x = node->offset, y = outputOffset; + while(x < sourceSize && y < targetSize && sourceData[x++] == targetData[y++]) length++; + if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = SourceCopy; + node = node->next; + } + } + + { //target copy + Node *node = targetTree[symbol]; + while(node) { + unsigned length = 0, x = node->offset, y = outputOffset; + while(y < targetSize && targetData[x++] == targetData[y++]) length++; + if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = TargetCopy; + node = node->next; + } + + //target tree append + node = new Node; + node->offset = outputOffset; + node->next = targetTree[symbol]; + targetTree[symbol] = node; + } + + { //target read + if(maxLength < 4) { + maxLength = min((unsigned)Granularity, targetSize - outputOffset); + mode = TargetRead; + } + } + + if(mode != TargetRead) targetReadFlush(); + + switch(mode) { + case SourceRead: + encode(SourceRead | ((maxLength - 1) << 2)); + break; + case TargetRead: + //delay write to group sequential TargetRead commands into one + targetReadLength += maxLength; + break; + case SourceCopy: + case TargetCopy: + encode(mode | ((maxLength - 1) << 2)); + signed relativeOffset; + if(mode == SourceCopy) { + relativeOffset = maxOffset - sourceRelativeOffset; + sourceRelativeOffset = maxOffset + maxLength; + } else { + relativeOffset = maxOffset - targetRelativeOffset; + targetRelativeOffset = maxOffset + maxLength; + } + encode((relativeOffset < 0) | (abs(relativeOffset) << 1)); + break; + } + + outputOffset += maxLength; + } + + targetReadFlush(); + + sourceChecksum = ~sourceChecksum; + for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n); + uint32_t targetChecksum = crc32_calculate(targetData, targetSize); + for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n); + uint32_t outputChecksum = ~modifyChecksum; + for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n); + + modifyFile.close(); + return true; +} + +} + +#endif diff --git a/nall/bps/linear.hpp b/nall/bps/linear.hpp new file mode 100755 index 00000000..df840283 --- /dev/null +++ b/nall/bps/linear.hpp @@ -0,0 +1,152 @@ +#ifndef NALL_BPS_LINEAR_HPP +#define NALL_BPS_LINEAR_HPP + +#include +#include +#include +#include +#include + +namespace nall { + +struct bpslinear { + inline void source(const uint8_t *data, unsigned size); + inline void target(const uint8_t *data, unsigned size); + + inline bool source(const string &filename); + inline bool target(const string &filename); + inline bool create(const string &filename, const string &metadata = ""); + +protected: + enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy }; + enum : unsigned { Granularity = 1 }; + + filemap sourceFile; + const uint8_t *sourceData; + unsigned sourceSize; + + filemap targetFile; + const uint8_t *targetData; + unsigned targetSize; +}; + +void bpslinear::source(const uint8_t *data, unsigned size) { + sourceData = data; + sourceSize = size; +} + +void bpslinear::target(const uint8_t *data, unsigned size) { + targetData = data; + targetSize = size; +} + +bool bpslinear::source(const string &filename) { + if(sourceFile.open(filename, filemap::mode::read) == false) return false; + source(sourceFile.data(), sourceFile.size()); + return true; +} + +bool bpslinear::target(const string &filename) { + if(targetFile.open(filename, filemap::mode::read) == false) return false; + target(targetFile.data(), targetFile.size()); + return true; +} + +bool bpslinear::create(const string &filename, const string &metadata) { + file modifyFile; + if(modifyFile.open(filename, file::mode::write) == false) return false; + + uint32_t modifyChecksum = ~0; + unsigned targetRelativeOffset = 0, outputOffset = 0; + + auto write = [&](uint8_t data) { + modifyFile.write(data); + modifyChecksum = crc32_adjust(modifyChecksum, data); + }; + + auto encode = [&](uint64_t data) { + while(true) { + uint64_t x = data & 0x7f; + data >>= 7; + if(data == 0) { + write(0x80 | x); + break; + } + write(x); + data--; + } + }; + + unsigned targetReadLength = 0; + + auto targetReadFlush = [&]() { + if(targetReadLength) { + encode(TargetRead | ((targetReadLength - 1) << 2)); + unsigned offset = outputOffset - targetReadLength; + while(targetReadLength) write(targetData[offset++]), targetReadLength--; + } + }; + + write('B'); + write('P'); + write('S'); + write('1'); + + encode(sourceSize); + encode(targetSize); + + unsigned markupSize = metadata.length(); + encode(markupSize); + for(unsigned n = 0; n < markupSize; n++) write(metadata[n]); + + while(outputOffset < targetSize) { + unsigned sourceLength = 0; + for(unsigned n = 0; outputOffset + n < min(sourceSize, targetSize); n++) { + if(sourceData[outputOffset + n] != targetData[outputOffset + n]) break; + sourceLength++; + } + + unsigned rleLength = 0; + for(unsigned n = 1; outputOffset + n < targetSize; n++) { + if(targetData[outputOffset] != targetData[outputOffset + n]) break; + rleLength++; + } + + if(rleLength >= 4) { + //write byte to repeat + targetReadLength++; + outputOffset++; + targetReadFlush(); + + //copy starting from repetition byte + encode(TargetCopy | ((rleLength - 1) << 2)); + unsigned relativeOffset = (outputOffset - 1) - targetRelativeOffset; + encode(relativeOffset << 1); + outputOffset += rleLength; + targetRelativeOffset = outputOffset - 1; + } else if(sourceLength >= 4) { + targetReadFlush(); + encode(SourceRead | ((sourceLength - 1) << 2)); + outputOffset += sourceLength; + } else { + targetReadLength += Granularity; + outputOffset += Granularity; + } + } + + targetReadFlush(); + + uint32_t sourceChecksum = crc32_calculate(sourceData, sourceSize); + for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n); + uint32_t targetChecksum = crc32_calculate(targetData, targetSize); + for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n); + uint32_t outputChecksum = ~modifyChecksum; + for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n); + + modifyFile.close(); + return true; +} + +} + +#endif diff --git a/nall/bps/metadata.hpp b/nall/bps/metadata.hpp new file mode 100755 index 00000000..46759e6f --- /dev/null +++ b/nall/bps/metadata.hpp @@ -0,0 +1,121 @@ +#ifndef NALL_BPS_METADATA_HPP +#define NALL_BPS_METADATA_HPP + +#include +#include +#include +#include +#include + +namespace nall { + +struct bpsmetadata { + inline bool load(const string &filename); + inline bool save(const string &filename, const string &metadata); + inline string metadata() const; + +protected: + file sourceFile; + string metadataString; +}; + +bool bpsmetadata::load(const string &filename) { + if(sourceFile.open(filename, file::mode::read) == false) return false; + + auto read = [&]() -> uint8_t { + return sourceFile.read(); + }; + + auto decode = [&]() -> uint64_t { + uint64_t data = 0, shift = 1; + while(true) { + uint8_t x = read(); + data += (x & 0x7f) * shift; + if(x & 0x80) break; + shift <<= 7; + data += shift; + } + return data; + }; + + if(read() != 'B') return false; + if(read() != 'P') return false; + if(read() != 'S') return false; + if(read() != '1') return false; + decode(); + decode(); + unsigned metadataSize = decode(); + char data[metadataSize + 1]; + for(unsigned n = 0; n < metadataSize; n++) data[n] = read(); + data[metadataSize] = 0; + metadataString = (const char*)data; + + return true; +} + +bool bpsmetadata::save(const string &filename, const string &metadata) { + file targetFile; + if(targetFile.open(filename, file::mode::write) == false) return false; + if(sourceFile.open() == false) return false; + sourceFile.seek(0); + + auto read = [&]() -> uint8_t { + return sourceFile.read(); + }; + + auto decode = [&]() -> uint64_t { + uint64_t data = 0, shift = 1; + while(true) { + uint8_t x = read(); + data += (x & 0x7f) * shift; + if(x & 0x80) break; + shift <<= 7; + data += shift; + } + return data; + }; + + uint32_t checksum = ~0; + + auto write = [&](uint8_t data) { + targetFile.write(data); + checksum = crc32_adjust(checksum, data); + }; + + auto encode = [&](uint64_t data) { + while(true) { + uint64_t x = data & 0x7f; + data >>= 7; + if(data == 0) { + write(0x80 | x); + break; + } + write(x); + data--; + } + }; + + for(unsigned n = 0; n < 4; n++) write(read()); + encode(decode()); + encode(decode()); + unsigned sourceLength = decode(); + unsigned targetLength = metadata.length(); + encode(targetLength); + sourceFile.seek(sourceLength, file::index::relative); + for(unsigned n = 0; n < targetLength; n++) write(metadata[n]); + unsigned length = sourceFile.size() - sourceFile.offset() - 4; + for(unsigned n = 0; n < length; n++) write(read()); + uint32_t outputChecksum = ~checksum; + for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n); + + targetFile.close(); + return true; +} + +string bpsmetadata::metadata() const { + return metadataString; +} + +} + +#endif diff --git a/nall/bps/patch.hpp b/nall/bps/patch.hpp new file mode 100755 index 00000000..85c4dcae --- /dev/null +++ b/nall/bps/patch.hpp @@ -0,0 +1,219 @@ +#ifndef NALL_BPS_PATCH_HPP +#define NALL_BPS_PATCH_HPP + +#include +#include +#include +#include +#include + +namespace nall { + +struct bpspatch { + inline bool modify(const uint8_t *data, unsigned size); + inline void source(const uint8_t *data, unsigned size); + inline void target(uint8_t *data, unsigned size); + + inline bool modify(const string &filename); + inline bool source(const string &filename); + inline bool target(const string &filename); + + inline string metadata() const; + inline unsigned size() const; + + enum result : unsigned { + unknown, + success, + patch_too_small, + patch_invalid_header, + source_too_small, + target_too_small, + source_checksum_invalid, + target_checksum_invalid, + patch_checksum_invalid, + }; + + inline result apply(); + +protected: + enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy }; + + filemap modifyFile; + const uint8_t *modifyData; + unsigned modifySize; + + filemap sourceFile; + const uint8_t *sourceData; + unsigned sourceSize; + + filemap targetFile; + uint8_t *targetData; + unsigned targetSize; + + unsigned modifySourceSize; + unsigned modifyTargetSize; + unsigned modifyMarkupSize; + string metadataString; +}; + +bool bpspatch::modify(const uint8_t *data, unsigned size) { + if(size < 19) return false; + modifyData = data; + modifySize = size; + + unsigned offset = 4; + auto decode = [&]() -> uint64_t { + uint64_t data = 0, shift = 1; + while(true) { + uint8_t x = modifyData[offset++]; + data += (x & 0x7f) * shift; + if(x & 0x80) break; + shift <<= 7; + data += shift; + } + return data; + }; + + modifySourceSize = decode(); + modifyTargetSize = decode(); + modifyMarkupSize = decode(); + + char buffer[modifyMarkupSize + 1]; + for(unsigned n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++]; + buffer[modifyMarkupSize] = 0; + metadataString = (const char*)buffer; + + return true; +} + +void bpspatch::source(const uint8_t *data, unsigned size) { + sourceData = data; + sourceSize = size; +} + +void bpspatch::target(uint8_t *data, unsigned size) { + targetData = data; + targetSize = size; +} + +bool bpspatch::modify(const string &filename) { + if(modifyFile.open(filename, filemap::mode::read) == false) return false; + return modify(modifyFile.data(), modifyFile.size()); +} + +bool bpspatch::source(const string &filename) { + if(sourceFile.open(filename, filemap::mode::read) == false) return false; + source(sourceFile.data(), sourceFile.size()); + return true; +} + +bool bpspatch::target(const string &filename) { + file fp; + if(fp.open(filename, file::mode::write) == false) return false; + fp.truncate(modifyTargetSize); + fp.close(); + + if(targetFile.open(filename, filemap::mode::readwrite) == false) return false; + target(targetFile.data(), targetFile.size()); + return true; +} + +string bpspatch::metadata() const { + return metadataString; +} + +unsigned bpspatch::size() const { + return modifyTargetSize; +} + +bpspatch::result bpspatch::apply() { + if(modifySize < 19) return result::patch_too_small; + + uint32_t modifyChecksum = ~0, targetChecksum = ~0; + unsigned modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0; + + auto read = [&]() -> uint8_t { + uint8_t data = modifyData[modifyOffset++]; + modifyChecksum = crc32_adjust(modifyChecksum, data); + return data; + }; + + auto decode = [&]() -> uint64_t { + uint64_t data = 0, shift = 1; + while(true) { + uint8_t x = read(); + data += (x & 0x7f) * shift; + if(x & 0x80) break; + shift <<= 7; + data += shift; + } + return data; + }; + + auto write = [&](uint8_t data) { + targetData[outputOffset++] = data; + targetChecksum = crc32_adjust(targetChecksum, data); + }; + + if(read() != 'B') return result::patch_invalid_header; + if(read() != 'P') return result::patch_invalid_header; + if(read() != 'S') return result::patch_invalid_header; + if(read() != '1') return result::patch_invalid_header; + + modifySourceSize = decode(); + modifyTargetSize = decode(); + modifyMarkupSize = decode(); + for(unsigned n = 0; n < modifyMarkupSize; n++) read(); + + if(modifySourceSize > sourceSize) return result::source_too_small; + if(modifyTargetSize > targetSize) return result::target_too_small; + + while(modifyOffset < modifySize - 12) { + unsigned length = decode(); + unsigned mode = length & 3; + length = (length >> 2) + 1; + + switch(mode) { + case SourceRead: + while(length--) write(sourceData[outputOffset]); + break; + case TargetRead: + while(length--) write(read()); + break; + case SourceCopy: + case TargetCopy: + signed offset = decode(); + bool negative = offset & 1; + offset >>= 1; + if(negative) offset = -offset; + + if(mode == SourceCopy) { + sourceRelativeOffset += offset; + while(length--) write(sourceData[sourceRelativeOffset++]); + } else { + targetRelativeOffset += offset; + while(length--) write(targetData[targetRelativeOffset++]); + } + break; + } + } + + uint32_t modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0; + for(unsigned n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n; + for(unsigned n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n; + uint32_t checksum = ~modifyChecksum; + for(unsigned n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n; + + uint32_t sourceChecksum = crc32_calculate(sourceData, modifySourceSize); + targetChecksum = ~targetChecksum; + + if(sourceChecksum != modifySourceChecksum) return result::source_checksum_invalid; + if(targetChecksum != modifyTargetChecksum) return result::target_checksum_invalid; + if(checksum != modifyModifyChecksum) return result::patch_checksum_invalid; + + return result::success; +} + +} + +#endif diff --git a/nall/compositor.hpp b/nall/compositor.hpp new file mode 100755 index 00000000..ff6a6ea6 --- /dev/null +++ b/nall/compositor.hpp @@ -0,0 +1,79 @@ +#ifndef NALL_COMPOSITOR_HPP +#define NALL_COMPOSITOR_HPP + +#include + +namespace nall { + +struct compositor { + inline static bool enabled(); + inline static bool enable(bool status); +}; + +#if defined(PLATFORM_X) + +bool compositor::enabled() { + FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r"); + if(fp == 0) return false; + + char buffer[512]; + if(fgets(buffer, sizeof buffer, fp) == 0) return false; + + if(!memcmp(buffer, "true", 4)) return true; + return false; +} + +bool compositor::enable(bool status) { + FILE *fp; + if(status) { + fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r"); + } else { + fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'", "r"); + } + if(fp == 0) return false; + pclose(fp); + return true; +} + +#elif defined(PLATFORM_WINDOWS) + +bool compositor::enabled() { + HMODULE module = GetModuleHandleW(L"dwmapi"); + if(module == 0) module = LoadLibraryW(L"dwmapi"); + if(module == 0) return false; + + auto pDwmIsCompositionEnabled = (HRESULT (WINAPI*)(BOOL*))GetProcAddress(module, "DwmIsCompositionEnabled"); + if(pDwmIsCompositionEnabled == 0) return false; + + BOOL result; + if(pDwmIsCompositionEnabled(&result) != S_OK) return false; + return result; +} + +bool compositor::enable(bool status) { + HMODULE module = GetModuleHandleW(L"dwmapi"); + if(module == 0) module = LoadLibraryW(L"dwmapi"); + if(module == 0) return false; + + auto pDwmEnableComposition = (HRESULT (WINAPI*)(UINT))GetProcAddress(module, "DwmEnableComposition"); + if(pDwmEnableComposition == 0) return false; + + if(pDwmEnableComposition(status) != S_OK) return false; + return true; +} + +#else + +bool compositor::enabled() { + return false; +} + +bool compositor::enable(bool) { + return false; +} + +#endif + +} + +#endif diff --git a/nall/config.hpp b/nall/config.hpp new file mode 100755 index 00000000..0c6602df --- /dev/null +++ b/nall/config.hpp @@ -0,0 +1,123 @@ +#ifndef NALL_CONFIG_HPP +#define NALL_CONFIG_HPP + +#include +#include +#include + +namespace nall { + namespace configuration_traits { + template struct is_boolean { enum { value = false }; }; + template<> struct is_boolean { enum { value = true }; }; + + template struct is_signed { enum { value = false }; }; + template<> struct is_signed { enum { value = true }; }; + + template struct is_unsigned { enum { value = false }; }; + template<> struct is_unsigned { enum { value = true }; }; + + template struct is_double { enum { value = false }; }; + template<> struct is_double { enum { value = true }; }; + + template struct is_string { enum { value = false }; }; + template<> struct is_string { enum { value = true }; }; + } + + class configuration { + public: + enum type_t { boolean_t, signed_t, unsigned_t, double_t, string_t, unknown_t }; + struct item_t { + uintptr_t data; + string name; + string desc; + type_t type; + + string get() const { + switch(type) { + case boolean_t: return { *(bool*)data }; + case signed_t: return { *(signed*)data }; + case unsigned_t: return { *(unsigned*)data }; + case double_t: return { *(double*)data }; + case string_t: return { "\"", *(string*)data, "\"" }; + } + return "???"; + } + + void set(string s) { + switch(type) { + case boolean_t: *(bool*)data = (s == "true"); break; + case signed_t: *(signed*)data = integer(s); break; + case unsigned_t: *(unsigned*)data = decimal(s); break; + case double_t: *(double*)data = fp(s); break; + case string_t: s.trim("\""); *(string*)data = s; break; + } + } + }; + linear_vector list; + + template + void attach(T &data, const char *name, const char *desc = "") { + unsigned n = list.size(); + list[n].data = (uintptr_t)&data; + list[n].name = name; + list[n].desc = desc; + + if(configuration_traits::is_boolean::value) list[n].type = boolean_t; + else if(configuration_traits::is_signed::value) list[n].type = signed_t; + else if(configuration_traits::is_unsigned::value) list[n].type = unsigned_t; + else if(configuration_traits::is_double::value) list[n].type = double_t; + else if(configuration_traits::is_string::value) list[n].type = string_t; + else list[n].type = unknown_t; + } + + virtual bool load(const string &filename) { + string data; + if(data.readfile(filename) == true) { + data.replace("\r", ""); + lstring line; + line.split("\n", data); + + for(unsigned i = 0; i < line.size(); i++) { + if(auto position = qstrpos(line[i], "#")) line[i][position()] = 0; + if(!qstrpos(line[i], " = ")) continue; + + lstring part; + part.qsplit(" = ", line[i]); + part[0].trim(); + part[1].trim(); + + for(unsigned n = 0; n < list.size(); n++) { + if(part[0] == list[n].name) { + list[n].set(part[1]); + break; + } + } + } + + return true; + } else { + return false; + } + } + + virtual bool save(const string &filename) const { + file fp; + if(fp.open(filename, file::mode::write)) { + for(unsigned i = 0; i < list.size(); i++) { + string output; + output.append(list[i].name, " = ", list[i].get()); + if(list[i].desc != "") output.append(" # ", list[i].desc); + output.append("\r\n"); + fp.print(output); + } + + fp.close(); + return true; + } else { + return false; + } + } + }; +} + +#endif diff --git a/nall/crc32.hpp b/nall/crc32.hpp new file mode 100755 index 00000000..ad36fbf6 --- /dev/null +++ b/nall/crc32.hpp @@ -0,0 +1,66 @@ +#ifndef NALL_CRC32_HPP +#define NALL_CRC32_HPP + +#include + +namespace nall { + const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + + inline uint32_t crc32_adjust(uint32_t crc32, uint8_t input) { + return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff]; + } + + inline uint32_t crc32_calculate(const uint8_t *data, unsigned length) { + uint32_t crc32 = ~0; + for(unsigned i = 0; i < length; i++) { + crc32 = crc32_adjust(crc32, data[i]); + } + return ~crc32; + } +} + +#endif diff --git a/nall/directory.hpp b/nall/directory.hpp new file mode 100755 index 00000000..31ca1e05 --- /dev/null +++ b/nall/directory.hpp @@ -0,0 +1,153 @@ +#ifndef NALL_DIRECTORY_HPP +#define NALL_DIRECTORY_HPP + +#include +#include +#include +#include + +#if defined(PLATFORM_WINDOWS) + #include +#else + #include + #include + #include +#endif + +namespace nall { + +struct directory { + static bool exists(const string &pathname); + static lstring folders(const string &pathname, const string &pattern = "*"); + static lstring files(const string &pathname, const string &pattern = "*"); + static lstring contents(const string &pathname, const string &pattern = "*"); +}; + +#if defined(PLATFORM_WINDOWS) + inline bool directory::exists(const string &pathname) { + DWORD result = GetFileAttributes(utf16_t(pathname)); + if(result == INVALID_FILE_ATTRIBUTES) return false; + return (result & FILE_ATTRIBUTE_DIRECTORY); + } + + inline lstring directory::folders(const string &pathname, const string &pattern) { + lstring list; + string path = pathname; + path.transform("/", "\\"); + if(!strend(path, "\\")) path.append("\\"); + path.append("*"); + HANDLE handle; + WIN32_FIND_DATA data; + handle = FindFirstFile(utf16_t(path), &data); + if(handle != INVALID_HANDLE_VALUE) { + if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) { + if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + string name = (const char*)utf8_t(data.cFileName); + if(wildcard(name, pattern)) list.append(name); + } + } + while(FindNextFile(handle, &data) != false) { + if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) { + if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + string name = (const char*)utf8_t(data.cFileName); + if(wildcard(name, pattern)) list.append(name); + } + } + } + FindClose(handle); + } + if(list.size() > 0) sort(&list[0], list.size()); + for(auto &name : list) name.append("/"); //must append after sorting + return list; + } + + inline lstring directory::files(const string &pathname, const string &pattern) { + lstring list; + string path = pathname; + path.transform("/", "\\"); + if(!strend(path, "\\")) path.append("\\"); + path.append("*"); + HANDLE handle; + WIN32_FIND_DATA data; + handle = FindFirstFile(utf16_t(path), &data); + if(handle != INVALID_HANDLE_VALUE) { + if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { + string name = (const char*)utf8_t(data.cFileName); + if(wildcard(name, pattern)) list.append(name); + } + while(FindNextFile(handle, &data) != false) { + if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { + string name = (const char*)utf8_t(data.cFileName); + if(wildcard(name, pattern)) list.append(name); + } + } + FindClose(handle); + } + if(list.size() > 0) sort(&list[0], list.size()); + return list; + } + + inline lstring directory::contents(const string &pathname, const string &pattern) { + lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files + lstring files = directory::files(pathname, pattern); + for(auto &file : files) folders.append(file); + return folders; + } +#else + inline bool directory::exists(const string &pathname) { + DIR *dp = opendir(pathname); + if(!dp) return false; + closedir(dp); + return true; + } + + inline lstring directory::folders(const string &pathname, const string &pattern) { + lstring list; + DIR *dp; + struct dirent *ep; + dp = opendir(pathname); + if(dp) { + while(ep = readdir(dp)) { + if(!strcmp(ep->d_name, ".")) continue; + if(!strcmp(ep->d_name, "..")) continue; + if(ep->d_type & DT_DIR) { + if(wildcard(ep->d_name, pattern)) list.append(ep->d_name); + } + } + closedir(dp); + } + if(list.size() > 0) sort(&list[0], list.size()); + for(auto &name : list) name.append("/"); //must append after sorting + return list; + } + + inline lstring directory::files(const string &pathname, const string &pattern) { + lstring list; + DIR *dp; + struct dirent *ep; + dp = opendir(pathname); + if(dp) { + while(ep = readdir(dp)) { + if(!strcmp(ep->d_name, ".")) continue; + if(!strcmp(ep->d_name, "..")) continue; + if((ep->d_type & DT_DIR) == 0) { + if(wildcard(ep->d_name, pattern)) list.append(ep->d_name); + } + } + closedir(dp); + } + if(list.size() > 0) sort(&list[0], list.size()); + return list; + } + + inline lstring directory::contents(const string &pathname, const string &pattern) { + lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files + lstring files = directory::files(pathname, pattern); + for(auto &file : files) folders.append(file); + return folders; + } +#endif + +} + +#endif diff --git a/nall/dl.hpp b/nall/dl.hpp new file mode 100755 index 00000000..3bd7d4d2 --- /dev/null +++ b/nall/dl.hpp @@ -0,0 +1,115 @@ +#ifndef NALL_DL_HPP +#define NALL_DL_HPP + +//dynamic linking support + +#include +#include +#include +#include + +#if defined(PLATFORM_X) || defined(PLATFORM_OSX) + #include +#elif defined(PLATFORM_WINDOWS) + #include + #include +#endif + +namespace nall { + struct library { + bool opened() const { return handle; } + bool open(const char*, const char* = ""); + bool open_absolute(const char*); + void* sym(const char*); + void close(); + + library() : handle(0) {} + ~library() { close(); } + + library& operator=(const library&) = delete; + library(const library&) = delete; + + private: + uintptr_t handle; + }; + + #if defined(PLATFORM_X) + inline bool library::open(const char *name, const char *path) { + if(handle) close(); + handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY); + if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY); + return handle; + } + + inline bool library::open_absolute(const char *name) { + if(handle) close(); + handle = (uintptr_t)dlopen(name, RTLD_LAZY); + return handle; + } + + inline void* library::sym(const char *name) { + if(!handle) return 0; + return dlsym((void*)handle, name); + } + + inline void library::close() { + if(!handle) return; + dlclose((void*)handle); + handle = 0; + } + #elif defined(PLATFORM_OSX) + inline bool library::open(const char *name, const char *path) { + if(handle) close(); + handle = (uintptr_t)dlopen(string(path, *path && !strend(path, "/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY); + if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY); + return handle; + } + + inline bool library::open_absolute(const char *name) { + if(handle) close(); + handle = (uintptr_t)dlopen(name, RTLD_LAZY); + return handle; + } + + inline void* library::sym(const char *name) { + if(!handle) return 0; + return dlsym((void*)handle, name); + } + + inline void library::close() { + if(!handle) return; + dlclose((void*)handle); + handle = 0; + } + #elif defined(PLATFORM_WINDOWS) + inline bool library::open(const char *name, const char *path) { + if(handle) close(); + string filepath(path, *path && !strend(path, "/") && !strend(path, "\\") ? "\\" : "", name, ".dll"); + handle = (uintptr_t)LoadLibraryW(utf16_t(filepath)); + return handle; + } + + inline bool library::open_absolute(const char *name) { + if(handle) close(); + handle = (uintptr_t)LoadLibraryW(utf16_t(name)); + return handle; + } + + inline void* library::sym(const char *name) { + if(!handle) return 0; + return (void*)GetProcAddress((HMODULE)handle, name); + } + + inline void library::close() { + if(!handle) return; + FreeLibrary((HMODULE)handle); + handle = 0; + } + #else + inline bool library::open(const char*, const char*) { return false; } + inline void* library::sym(const char*) { return 0; } + inline void library::close() {} + #endif +}; + +#endif diff --git a/nall/dsp.hpp b/nall/dsp.hpp new file mode 100755 index 00000000..a2400ec7 --- /dev/null +++ b/nall/dsp.hpp @@ -0,0 +1,13 @@ +#ifndef NALL_DSP_HPP +#define NALL_DSP_HPP + +#include +#ifdef __SSE__ + #include +#endif + +#define NALL_DSP_INTERNAL_HPP +#include +#undef NALL_DSP_INTERNAL_HPP + +#endif diff --git a/nall/dsp/buffer.hpp b/nall/dsp/buffer.hpp new file mode 100755 index 00000000..4386d0e9 --- /dev/null +++ b/nall/dsp/buffer.hpp @@ -0,0 +1,51 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +struct Buffer { + double **sample; + uint16_t rdoffset; + uint16_t wroffset; + unsigned channels; + + void setChannels(unsigned channels) { + for(unsigned c = 0; c < this->channels; c++) { + if(sample[c]) delete[] sample[c]; + } + if(sample) delete[] sample; + + this->channels = channels; + if(channels == 0) return; + + sample = new double*[channels]; + for(unsigned c = 0; c < channels; c++) { + sample[c] = new double[65536](); + } + } + + inline double& read(unsigned channel, signed offset = 0) { + return sample[channel][(uint16_t)(rdoffset + offset)]; + } + + inline double& write(unsigned channel, signed offset = 0) { + return sample[channel][(uint16_t)(wroffset + offset)]; + } + + inline void clear() { + for(unsigned c = 0; c < channels; c++) { + for(unsigned n = 0; n < 65536; n++) { + sample[c][n] = 0; + } + } + rdoffset = 0; + wroffset = 0; + } + + Buffer() { + channels = 0; + } + + ~Buffer() { + setChannels(0); + } +}; + +#endif diff --git a/nall/dsp/core.hpp b/nall/dsp/core.hpp new file mode 100755 index 00000000..a5b967b1 --- /dev/null +++ b/nall/dsp/core.hpp @@ -0,0 +1,167 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +#include +#include + +namespace nall { + +//precision: can be float, double or long double +#define real float + +struct DSP; + +struct Resampler { + DSP &dsp; + real frequency; + + virtual void setFrequency() = 0; + virtual void clear() = 0; + virtual void sample() = 0; + Resampler(DSP &dsp) : dsp(dsp) {} +}; + +struct DSP { + enum class ResampleEngine : unsigned { + Nearest, + Linear, + Cosine, + Cubic, + Hermite, + Average, + Sinc, + }; + + inline void setChannels(unsigned channels); + inline void setPrecision(unsigned precision); + inline void setFrequency(real frequency); //inputFrequency + inline void setVolume(real volume); + inline void setBalance(real balance); + + inline void setResampler(ResampleEngine resamplingEngine); + inline void setResamplerFrequency(real frequency); //outputFrequency + + inline void sample(signed channel[]); + inline bool pending(); + inline void read(signed channel[]); + + inline void clear(); + inline DSP(); + inline ~DSP(); + +protected: + friend class ResampleNearest; + friend class ResampleLinear; + friend class ResampleCosine; + friend class ResampleCubic; + friend class ResampleAverage; + friend class ResampleHermite; + friend class ResampleSinc; + + struct Settings { + unsigned channels; + unsigned precision; + real frequency; + real volume; + real balance; + + //internal + real intensity; + real intensityInverse; + } settings; + + Resampler *resampler; + inline void write(real channel[]); + + #include "buffer.hpp" + Buffer buffer; + Buffer output; + + inline void adjustVolume(); + inline void adjustBalance(); + inline signed clamp(const unsigned bits, const signed x); +}; + +#include "resample/nearest.hpp" +#include "resample/linear.hpp" +#include "resample/cosine.hpp" +#include "resample/cubic.hpp" +#include "resample/hermite.hpp" +#include "resample/average.hpp" +#include "resample/sinc.hpp" +#include "settings.hpp" + +void DSP::sample(signed channel[]) { + for(unsigned c = 0; c < settings.channels; c++) { + buffer.write(c) = (real)channel[c] * settings.intensityInverse; + } + buffer.wroffset++; + resampler->sample(); +} + +bool DSP::pending() { + return output.rdoffset != output.wroffset; +} + +void DSP::read(signed channel[]) { + adjustVolume(); + adjustBalance(); + + for(unsigned c = 0; c < settings.channels; c++) { + channel[c] = clamp(settings.precision, output.read(c) * settings.intensity); + } + output.rdoffset++; +} + +void DSP::write(real channel[]) { + for(unsigned c = 0; c < settings.channels; c++) { + output.write(c) = channel[c]; + } + output.wroffset++; +} + +void DSP::adjustVolume() { + for(unsigned c = 0; c < settings.channels; c++) { + output.read(c) *= settings.volume; + } +} + +void DSP::adjustBalance() { + if(settings.channels != 2) return; //TODO: support > 2 channels + if(settings.balance < 0.0) output.read(1) *= 1.0 + settings.balance; + if(settings.balance > 0.0) output.read(0) *= 1.0 - settings.balance; +} + +signed DSP::clamp(const unsigned bits, const signed x) { + const signed b = 1U << (bits - 1); + const signed m = (1U << (bits - 1)) - 1; + return (x > m) ? m : (x < -b) ? -b : x; +} + +void DSP::clear() { + buffer.clear(); + output.clear(); + resampler->clear(); +} + +DSP::DSP() { + setResampler(ResampleEngine::Hermite); + setResamplerFrequency(44100.0); + + setChannels(2); + setPrecision(16); + setFrequency(44100.0); + setVolume(1.0); + setBalance(0.0); + + clear(); +} + +DSP::~DSP() { + if(resampler) delete resampler; +} + +#undef real + +} + +#endif diff --git a/nall/dsp/resample/average.hpp b/nall/dsp/resample/average.hpp new file mode 100755 index 00000000..867b13bf --- /dev/null +++ b/nall/dsp/resample/average.hpp @@ -0,0 +1,72 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +struct ResampleAverage : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + inline void sampleLinear(); + ResampleAverage(DSP &dsp) : Resampler(dsp) {} + + real fraction; + real step; +}; + +void ResampleAverage::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleAverage::clear() { + fraction = 0.0; +} + +void ResampleAverage::sample() { + //can only average if input frequency >= output frequency + if(step < 1.0) return sampleLinear(); + + fraction += 1.0; + + real scalar = 1.0; + if(fraction > step) scalar = 1.0 - (fraction - step); + + for(unsigned c = 0; c < dsp.settings.channels; c++) { + dsp.output.write(c) += dsp.buffer.read(c) * scalar; + } + + if(fraction >= step) { + for(unsigned c = 0; c < dsp.settings.channels; c++) { + dsp.output.write(c) /= step; + } + dsp.output.wroffset++; + + fraction -= step; + for(unsigned c = 0; c < dsp.settings.channels; c++) { + dsp.output.write(c) = dsp.buffer.read(c) * fraction; + } + } + + dsp.buffer.rdoffset++; +} + +void ResampleAverage::sampleLinear() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -1); + real b = dsp.buffer.read(n, -0); + + real mu = fraction; + + channel[n] = a * (1.0 - mu) + b * mu; + } + + dsp.write(channel); + fraction += step; + } + + dsp.buffer.rdoffset++; + fraction -= 1.0; +} + +#endif diff --git a/nall/dsp/resample/cosine.hpp b/nall/dsp/resample/cosine.hpp new file mode 100755 index 00000000..3363d5f6 --- /dev/null +++ b/nall/dsp/resample/cosine.hpp @@ -0,0 +1,44 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +struct ResampleCosine : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleCosine(DSP &dsp) : Resampler(dsp) {} + + real fraction; + real step; +}; + +void ResampleCosine::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleCosine::clear() { + fraction = 0.0; +} + +void ResampleCosine::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -1); + real b = dsp.buffer.read(n, -0); + + real mu = fraction; + mu = (1.0 - cos(mu * 3.14159265)) / 2.0; + + channel[n] = a * (1.0 - mu) + b * mu; + } + + dsp.write(channel); + fraction += step; + } + + dsp.buffer.rdoffset++; + fraction -= 1.0; +} + +#endif diff --git a/nall/dsp/resample/cubic.hpp b/nall/dsp/resample/cubic.hpp new file mode 100755 index 00000000..bc4cc955 --- /dev/null +++ b/nall/dsp/resample/cubic.hpp @@ -0,0 +1,50 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +struct ResampleCubic : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleCubic(DSP &dsp) : Resampler(dsp) {} + + real fraction; + real step; +}; + +void ResampleCubic::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleCubic::clear() { + fraction = 0.0; +} + +void ResampleCubic::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -3); + real b = dsp.buffer.read(n, -2); + real c = dsp.buffer.read(n, -1); + real d = dsp.buffer.read(n, -0); + + real mu = fraction; + + real A = d - c - a + b; + real B = a - b - A; + real C = c - a; + real D = b; + + channel[n] = A * (mu * 3) + B * (mu * 2) + C * mu + D; + } + + dsp.write(channel); + fraction += step; + } + + dsp.buffer.rdoffset++; + fraction -= 1.0; +} + +#endif diff --git a/nall/dsp/resample/hermite.hpp b/nall/dsp/resample/hermite.hpp new file mode 100755 index 00000000..0cc9ba0e --- /dev/null +++ b/nall/dsp/resample/hermite.hpp @@ -0,0 +1,62 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +struct ResampleHermite : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleHermite(DSP &dsp) : Resampler(dsp) {} + + real fraction; + real step; +}; + +void ResampleHermite::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleHermite::clear() { + fraction = 0.0; +} + +void ResampleHermite::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -3); + real b = dsp.buffer.read(n, -2); + real c = dsp.buffer.read(n, -1); + real d = dsp.buffer.read(n, -0); + + const real tension = 0.0; //-1 = low, 0 = normal, +1 = high + const real bias = 0.0; //-1 = left, 0 = even, +1 = right + + real mu1, mu2, mu3, m0, m1, a0, a1, a2, a3; + + mu1 = fraction; + mu2 = mu1 * mu1; + mu3 = mu2 * mu1; + + m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0; + m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0; + m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0; + m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0; + + a0 = +2 * mu3 - 3 * mu2 + 1; + a1 = mu3 - 2 * mu2 + mu1; + a2 = mu3 - mu2; + a3 = -2 * mu3 + 3 * mu2; + + channel[n] = (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); + } + + dsp.write(channel); + fraction += step; + } + + dsp.buffer.rdoffset++; + fraction -= 1.0; +} + +#endif diff --git a/nall/dsp/resample/lib/sinc.hpp b/nall/dsp/resample/lib/sinc.hpp new file mode 100755 index 00000000..3e953679 --- /dev/null +++ b/nall/dsp/resample/lib/sinc.hpp @@ -0,0 +1,600 @@ +// If these types are changed to anything other than "float", you should comment out the SSE detection directives below +// so that the SSE code is not used. + +typedef float resample_coeff_t; // note: sizeof(resample_coeff_t) must be == to a power of 2, and not larger than 16 +typedef float resample_samp_t; + + +// ...but don't comment this single RESAMPLE_SSEREGPARM define out when disabling SSE. +#define RESAMPLE_SSEREGPARM + +#if defined(__SSE__) + #define SINCRESAMPLE_USE_SSE 1 + #ifndef __x86_64__ + #undef RESAMPLE_SSEREGPARM + #define RESAMPLE_SSEREGPARM __attribute__((sseregparm)) + #endif +#else + // TODO: altivec here +#endif + +namespace ResampleUtility +{ + inline void kaiser_window(double* io, int count, double beta); + inline void gen_sinc(double* out, int size, double cutoff, double kaiser); + inline void gen_sinc_os(double* out, int size, double cutoff, double kaiser); + inline void normalize(double* io, int size, double gain = 1.0); + + inline void* make_aligned(void* ptr, unsigned boundary); // boundary must be a power of 2 +} + +class SincResampleHR +{ + private: + + inline void Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d); + + inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM; + inline resample_samp_t read(void) RESAMPLE_SSEREGPARM; + inline bool output_avail(void); + + private: + + inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count); + + unsigned ratio; + unsigned num_convolutions; + + resample_coeff_t *coeffs; + std::vector coeffs_mem; + + // second half of ringbuffer should be copy of first half. + resample_samp_t *rb; + std::vector rb_mem; + + signed rb_readpos; + signed rb_writepos; + signed rb_in; + signed rb_eff_size; + + friend class SincResample; +}; + +class SincResample +{ + public: + + enum + { + QUALITY_LOW = 0, + QUALITY_MEDIUM = 2, + QUALITY_HIGH = 4 + }; + + inline SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality = QUALITY_HIGH); + + inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM; + inline resample_samp_t read(void) RESAMPLE_SSEREGPARM; + inline bool output_avail(void); + + private: + + inline void Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min); + + inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count) RESAMPLE_SSEREGPARM; + + unsigned num_convolutions; + unsigned num_phases; + + unsigned step_int; + double step_fract; + + double input_pos_fract; + + + std::vector coeffs; // Pointers into coeff_mem. + std::vector coeff_mem; + + + std::vector rb; // second half should be copy of first half. + signed rb_readpos; + signed rb_writepos; + signed rb_in; + + bool hr_used; + SincResampleHR hr; +}; + + +// +// Code: +// +//#include "resample.hpp" + +#if 0 +namespace bit +{ + inline unsigned round(unsigned x) { + if((x & (x - 1)) == 0) return x; + while(x & (x - 1)) x &= x - 1; + return x << 1; + } +} +#endif + +void SincResampleHR::Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d) +{ + const unsigned align_boundary = 16; + std::vector coeffs_tmp; + double cutoff; // 1.0 = f/2 + + ratio = ratio_arg; + + //num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) + 1) &~ 1; // round up to be even + num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) | 1); + + cutoff = (1.0 / ratio) - (d / num_convolutions); + +//printf("%d %d %.20f\n", ratio, num_convolutions, cutoff); + assert(num_convolutions > ratio); + + + // Generate windowed sinc of POWER + coeffs_tmp.resize(num_convolutions); + //ResampleUtility::gen_sinc(&coeffs_tmp[0], num_convolutions, cutoff, beta); + ResampleUtility::gen_sinc_os(&coeffs_tmp[0], num_convolutions, cutoff, beta); + ResampleUtility::normalize(&coeffs_tmp[0], num_convolutions); + + // Copy from coeffs_tmp to coeffs~ + // We multiply many coefficients at a time in the mac loop, so make sure the last few that don't really + // exist are allocated, zero'd mem. + + coeffs_mem.resize(((num_convolutions + 7) &~ 7) * sizeof(resample_coeff_t) + (align_boundary - 1)); + coeffs = (resample_coeff_t *)ResampleUtility::make_aligned(&coeffs_mem[0], align_boundary); + + + for(unsigned i = 0; i < num_convolutions; i++) + coeffs[i] = coeffs_tmp[i]; + + rb_eff_size = nall::bit::round(num_convolutions * 2) >> 1; + rb_readpos = 0; + rb_writepos = 0; + rb_in = 0; + + rb_mem.resize(rb_eff_size * 2 * sizeof(resample_samp_t) + (align_boundary - 1)); + rb = (resample_samp_t *)ResampleUtility::make_aligned(&rb_mem[0], align_boundary); +} + + +inline bool SincResampleHR::output_avail(void) +{ + return(rb_in >= (signed)num_convolutions); +} + +inline void SincResampleHR::write(resample_samp_t sample) +{ + assert(!output_avail()); + + rb[rb_writepos] = sample; + rb[rb_writepos + rb_eff_size] = sample; + rb_writepos = (rb_writepos + 1) & (rb_eff_size - 1); + rb_in++; +} + +resample_samp_t SincResampleHR::mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count) +{ +#if SINCRESAMPLE_USE_SSE + __m128 accum_veca[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; + + resample_samp_t accum; + + for(unsigned c = 0; c < count; c += 8) + { + for(unsigned i = 0; i < 2; i++) + { + __m128 co[2]; + __m128 w[2]; + + co[i] = _mm_load_ps(&coeff[c + i * 4]); + w[i] = _mm_load_ps(&wave[c + i * 4]); + + w[i] = _mm_mul_ps(w[i], co[i]); + + accum_veca[i] = _mm_add_ps(w[i], accum_veca[i]); + } + } + + __m128 accum_vec = _mm_add_ps(accum_veca[0], accum_veca[1]); //_mm_add_ps(_mm_add_ps(accum_veca[0], accum_veca[1]), _mm_add_ps(accum_veca[2], accum_veca[3])); + + accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6))); + accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6))); + + _mm_store_ss(&accum, accum_vec); + + return accum; +#else + resample_samp_t accum[4] = { 0, 0, 0, 0 }; + + for(unsigned c = 0; c < count; c+= 4) + { + accum[0] += wave[c + 0] * coeff[c + 0]; + accum[1] += wave[c + 1] * coeff[c + 1]; + accum[2] += wave[c + 2] * coeff[c + 2]; + accum[3] += wave[c + 3] * coeff[c + 3]; + } + + return (accum[0] + accum[1]) + (accum[2] + accum[3]); // don't mess with parentheses(assuming compiler doesn't already, which it may... + +#endif +} + + +resample_samp_t SincResampleHR::read(void) +{ + assert(output_avail()); + resample_samp_t ret; + + ret = mac(&rb[rb_readpos], &coeffs[0], num_convolutions); + + rb_readpos = (rb_readpos + ratio) & (rb_eff_size - 1); + rb_in -= ratio; + + return ret; +} + + +SincResample::SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality) +{ + const struct + { + double beta; + double d; + unsigned pn_nume; + unsigned phases_min; + } qtab[5] = + { + { 5.658, 3.62, 4096, 4 }, + { 6.764, 4.32, 8192, 4 }, + { 7.865, 5.0, 16384, 8 }, + { 8.960, 5.7, 32768, 16 }, + { 10.056, 6.4, 65536, 32 } + }; + + // Sanity checks + assert(ceil(input_rate) > 0); + assert(ceil(output_rate) > 0); + assert(ceil(input_rate / output_rate) <= 1024); + assert(ceil(output_rate / input_rate) <= 1024); + + // The simplistic number-of-phases calculation code doesn't work well enough for when desired_bandwidth is close to 1.0 and when + // upsampling. + assert(desired_bandwidth >= 0.25 && desired_bandwidth < 0.96); + assert(quality >= 0 && quality <= 4); + + hr_used = false; + +#if 1 + // Round down to the nearest multiple of 4(so wave buffer remains aligned) + // It also adjusts the effective intermediate sampling rate up slightly, so that the upper frequencies below f/2 + // aren't overly attenuated so much. In the future, we might want to do an FFT or something to choose the intermediate rate more accurately + // to virtually eliminate over-attenuation. + unsigned ioratio_rd = (unsigned)floor(input_rate / (output_rate * (1.0 + (1.0 - desired_bandwidth) / 2) )) & ~3; + + if(ioratio_rd >= 8) + { + hr.Init(ioratio_rd, desired_bandwidth, qtab[quality].beta, qtab[quality].d); //10.056, 6.4); + hr_used = true; + + input_rate /= ioratio_rd; + } +#endif + + Init(input_rate, output_rate, desired_bandwidth, qtab[quality].beta, qtab[quality].d, qtab[quality].pn_nume, qtab[quality].phases_min); +} + +void SincResample::Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min) +{ + const unsigned max_mult_atatime = 8; // multiply "granularity". must be power of 2. + const unsigned max_mult_minus1 = (max_mult_atatime - 1); + const unsigned conv_alignment_bytes = 16; // must be power of 2 + const double input_to_output_ratio = input_rate / output_rate; + const double output_to_input_ratio = output_rate / input_rate; + double cutoff; // 1.0 = input_rate / 2 + std::vector coeff_init_buffer; + + // Round up num_convolutions to be even. + if(output_rate > input_rate) + num_convolutions = ((unsigned)ceil(d / (1.0 - desired_bandwidth)) + 1) & ~1; + else + num_convolutions = ((unsigned)ceil(d / (output_to_input_ratio * (1.0 - desired_bandwidth))) + 1) & ~1; + + if(output_rate > input_rate) // Upsampling + cutoff = desired_bandwidth; + else // Downsampling + cutoff = output_to_input_ratio * desired_bandwidth; + + // Round up to be even. + num_phases = (std::max(pn_nume / num_convolutions, phases_min) + 1) &~1; + + // Adjust cutoff to account for the multiple phases. + cutoff = cutoff / num_phases; + + assert((num_convolutions & 1) == 0); + assert((num_phases & 1) == 0); + +// fprintf(stderr, "num_convolutions=%u, num_phases=%u, total expected coeff byte size=%lu\n", num_convolutions, num_phases, +// (long)((num_phases + 2) * ((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * sizeof(float) + conv_alignment_bytes)); + + coeff_init_buffer.resize(num_phases * num_convolutions); + + coeffs.resize(num_phases + 1 + 1); + + coeff_mem.resize((num_phases + 1 + 1) * ((num_convolutions + max_mult_minus1) &~ max_mult_minus1) * sizeof(resample_coeff_t) + conv_alignment_bytes); + + // Assign aligned pointers into coeff_mem + { + resample_coeff_t *base_ptr = (resample_coeff_t *)ResampleUtility::make_aligned(&coeff_mem[0], conv_alignment_bytes); + + for(unsigned phase = 0; phase < (num_phases + 1 + 1); phase++) + { + coeffs[phase] = base_ptr + (((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * phase); + } + } + + ResampleUtility::gen_sinc(&coeff_init_buffer[0], num_phases * num_convolutions, cutoff, beta); + ResampleUtility::normalize(&coeff_init_buffer[0], num_phases * num_convolutions, num_phases); + + // Reorder coefficients to allow for more efficient convolution. + for(int phase = -1; phase < ((int)num_phases + 1); phase++) + { + for(int conv = 0; conv < (int)num_convolutions; conv++) + { + double coeff; + + if(phase == -1 && conv == 0) + coeff = 0; + else if(phase == (int)num_phases && conv == ((int)num_convolutions - 1)) + coeff = 0; + else + coeff = coeff_init_buffer[conv * num_phases + phase]; + + coeffs[phase + 1][conv] = coeff; + } + } + + // Free a bit of mem + coeff_init_buffer.resize(0); + + step_int = floor(input_to_output_ratio); + step_fract = input_to_output_ratio - step_int; + + input_pos_fract = 0; + + // Do NOT use rb.size() later in the code, since it'll include the padding. + // We should only need one "max_mult_minus1" here, not two, since it won't matter if it over-reads(due to doing "max_mult_atatime" multiplications at a time + // rather than just 1, in which case this over-read wouldn't happen), from the first half into the duplicated half, + // since those corresponding coefficients will be zero anyway; this is just to handle the case of reading off the end of the duplicated half to + // prevent illegal memory accesses. + rb.resize(num_convolutions * 2 + max_mult_minus1); + + rb_readpos = 0; + rb_writepos = 0; + rb_in = 0; +} + +resample_samp_t SincResample::mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count) +{ + resample_samp_t accum = 0; +#if SINCRESAMPLE_USE_SSE + __m128 accum_vec_a[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; + __m128 accum_vec_b[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; + + for(unsigned c = 0; c < count; c += 8) //8) //4) + { + __m128 coeff_a[2]; + __m128 coeff_b[2]; + __m128 w[2]; + __m128 result_a[2], result_b[2]; + + for(unsigned i = 0; i < 2; i++) + { + coeff_a[i] = _mm_load_ps(&coeffs_a[c + (i * 4)]); + coeff_b[i] = _mm_load_ps(&coeffs_b[c + (i * 4)]); + w[i] = _mm_loadu_ps(&wave[c + (i * 4)]); + + result_a[i] = _mm_mul_ps(coeff_a[i], w[i]); + result_b[i] = _mm_mul_ps(coeff_b[i], w[i]); + + accum_vec_a[i] = _mm_add_ps(result_a[i], accum_vec_a[i]); + accum_vec_b[i] = _mm_add_ps(result_b[i], accum_vec_b[i]); + } + } + + __m128 accum_vec, av_a, av_b; + __m128 mult_a_vec = _mm_set1_ps(1.0 - ffract); + __m128 mult_b_vec = _mm_set1_ps(ffract); + + av_a = _mm_mul_ps(mult_a_vec, /*accum_vec_a[0]);*/ _mm_add_ps(accum_vec_a[0], accum_vec_a[1])); + av_b = _mm_mul_ps(mult_b_vec, /*accum_vec_b[0]);*/ _mm_add_ps(accum_vec_b[0], accum_vec_b[1])); + + accum_vec = _mm_add_ps(av_a, av_b); + + accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6))); + accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6))); + + _mm_store_ss(&accum, accum_vec); +#else + resample_coeff_t mult_a = 1.0 - ffract; + resample_coeff_t mult_b = ffract; + + for(unsigned c = 0; c < count; c += 4) + { + accum += wave[c + 0] * (coeffs_a[c + 0] * mult_a + coeffs_b[c + 0] * mult_b); + accum += wave[c + 1] * (coeffs_a[c + 1] * mult_a + coeffs_b[c + 1] * mult_b); + accum += wave[c + 2] * (coeffs_a[c + 2] * mult_a + coeffs_b[c + 2] * mult_b); + accum += wave[c + 3] * (coeffs_a[c + 3] * mult_a + coeffs_b[c + 3] * mult_b); + } +#endif + + return accum; +} + +inline bool SincResample::output_avail(void) +{ + return(rb_in >= (int)num_convolutions); +} + +resample_samp_t SincResample::read(void) +{ + assert(output_avail()); + double phase = input_pos_fract * num_phases - 0.5; + signed phase_int = (signed)floor(phase); + double phase_fract = phase - phase_int; + unsigned phase_a = num_phases - 1 - phase_int; + unsigned phase_b = phase_a - 1; + resample_samp_t ret; + + ret = mac(&rb[rb_readpos], &coeffs[phase_a + 1][0], &coeffs[phase_b + 1][0], phase_fract, num_convolutions); + + unsigned int_increment = step_int; + + input_pos_fract += step_fract; + int_increment += floor(input_pos_fract); + input_pos_fract -= floor(input_pos_fract); + + rb_readpos = (rb_readpos + int_increment) % num_convolutions; + rb_in -= int_increment; + + return ret; +} + +inline void SincResample::write(resample_samp_t sample) +{ + assert(!output_avail()); + + if(hr_used) + { + hr.write(sample); + + if(hr.output_avail()) + { + sample = hr.read(); + } + else + { + return; + } + } + + rb[rb_writepos + 0 * num_convolutions] = sample; + rb[rb_writepos + 1 * num_convolutions] = sample; + rb_writepos = (rb_writepos + 1) % num_convolutions; + rb_in++; +} + +void ResampleUtility::kaiser_window( double* io, int count, double beta) +{ + int const accuracy = 24; //16; //12; + + double* end = io + count; + + double beta2 = beta * beta * (double) -0.25; + double to_fract = beta2 / ((double) count * count); + double i = 0; + double rescale = 0; // Doesn't need an initializer, to shut up gcc + + for ( ; io < end; ++io, i += 1 ) + { + double x = i * i * to_fract - beta2; + double u = x; + double k = x + 1; + + double n = 2; + do + { + u *= x / (n * n); + n += 1; + k += u; + } + while ( k <= u * (1 << accuracy) ); + + if ( !i ) + rescale = 1 / k; // otherwise values get large + + *io *= k * rescale; + } +} + +void ResampleUtility::gen_sinc(double* out, int size, double cutoff, double kaiser) +{ + assert( size % 2 == 0 ); // size must be even + + int const half_size = size / 2; + double* const mid = &out [half_size]; + + // Generate right half of sinc + for ( int i = 0; i < half_size; i++ ) + { + double angle = (i * 2 + 1) * (M_PI / 2); + mid [i] = sin( angle * cutoff ) / angle; + } + + kaiser_window( mid, half_size, kaiser ); + + // Mirror for left half + for ( int i = 0; i < half_size; i++ ) + out [i] = mid [half_size - 1 - i]; +} + +void ResampleUtility::gen_sinc_os(double* out, int size, double cutoff, double kaiser) +{ + assert( size % 2 == 1); // size must be odd + + for(int i = 0; i < size; i++) + { + if(i == (size / 2)) + out[i] = 2 * M_PI * (cutoff / 2); //0.078478; //1.0; //sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2)); + else + out[i] = sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2)); + +// out[i] *= 0.3635819 - 0.4891775 * cos(2 * M_PI * i / (size - 1)) + 0.1365995 * cos(4 * M_PI * i / (size - 1)) - 0.0106411 * cos(6 * M_PI * i / (size - 1)); +//0.42 - 0.5 * cos(2 * M_PI * i / (size - 1)) + 0.08 * cos(4 * M_PI * i / (size - 1)); + +// printf("%d %f\n", i, out[i]); + } + + kaiser_window(&out[size / 2], size / 2 + 1, kaiser); + + // Mirror for left half + for ( int i = 0; i < size / 2; i++ ) + out [i] = out [size - 1 - i]; + +} + +void ResampleUtility::normalize(double* io, int size, double gain) +{ + double sum = 0; + for ( int i = 0; i < size; i++ ) + sum += io [i]; + + double scale = gain / sum; + for ( int i = 0; i < size; i++ ) + io [i] *= scale; +} + +void* ResampleUtility::make_aligned(void* ptr, unsigned boundary) +{ + unsigned char* null_ptr = (unsigned char *)NULL; + unsigned char* uc_ptr = (unsigned char *)ptr; + + uc_ptr += (boundary - ((uc_ptr - null_ptr) & (boundary - 1))) & (boundary - 1); + + //while((uc_ptr - null_ptr) & (boundary - 1)) + // uc_ptr++; + + //printf("%16llx %16llx\n", (unsigned long long)ptr, (unsigned long long)uc_ptr); + + assert((uc_ptr - (unsigned char *)ptr) < boundary && (uc_ptr >= (unsigned char *)ptr)); + + return uc_ptr; +} diff --git a/nall/dsp/resample/linear.hpp b/nall/dsp/resample/linear.hpp new file mode 100755 index 00000000..3c2dc9e6 --- /dev/null +++ b/nall/dsp/resample/linear.hpp @@ -0,0 +1,43 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +struct ResampleLinear : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleLinear(DSP &dsp) : Resampler(dsp) {} + + real fraction; + real step; +}; + +void ResampleLinear::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleLinear::clear() { + fraction = 0.0; +} + +void ResampleLinear::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -1); + real b = dsp.buffer.read(n, -0); + + real mu = fraction; + + channel[n] = a * (1.0 - mu) + b * mu; + } + + dsp.write(channel); + fraction += step; + } + + dsp.buffer.rdoffset++; + fraction -= 1.0; +} + +#endif diff --git a/nall/dsp/resample/nearest.hpp b/nall/dsp/resample/nearest.hpp new file mode 100755 index 00000000..14b401eb --- /dev/null +++ b/nall/dsp/resample/nearest.hpp @@ -0,0 +1,43 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +struct ResampleNearest : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleNearest(DSP &dsp) : Resampler(dsp) {} + + real fraction; + real step; +}; + +void ResampleNearest::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleNearest::clear() { + fraction = 0.0; +} + +void ResampleNearest::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -1); + real b = dsp.buffer.read(n, -0); + + real mu = fraction; + + channel[n] = mu < 0.5 ? a : b; + } + + dsp.write(channel); + fraction += step; + } + + dsp.buffer.rdoffset++; + fraction -= 1.0; +} + +#endif diff --git a/nall/dsp/resample/sinc.hpp b/nall/dsp/resample/sinc.hpp new file mode 100755 index 00000000..a77a1eeb --- /dev/null +++ b/nall/dsp/resample/sinc.hpp @@ -0,0 +1,54 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +#include "lib/sinc.hpp" + +struct ResampleSinc : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + inline ResampleSinc(DSP &dsp); + +private: + inline void remakeSinc(); + SincResample *sinc_resampler[8]; +}; + +void ResampleSinc::setFrequency() { + remakeSinc(); +} + +void ResampleSinc::clear() { + remakeSinc(); +} + +void ResampleSinc::sample() { + for(unsigned c = 0; c < dsp.settings.channels; c++) { + sinc_resampler[c]->write(dsp.buffer.read(c)); + } + + if(sinc_resampler[0]->output_avail()) { + do { + for(unsigned c = 0; c < dsp.settings.channels; c++) { + dsp.output.write(c) = sinc_resampler[c]->read(); + } + dsp.output.wroffset++; + } while(sinc_resampler[0]->output_avail()); + } + + dsp.buffer.rdoffset++; +} + +ResampleSinc::ResampleSinc(DSP &dsp) : Resampler(dsp) { + for(unsigned n = 0; n < 8; n++) sinc_resampler[n] = 0; +} + +void ResampleSinc::remakeSinc() { + assert(dsp.settings.channels < 8); + + for(unsigned c = 0; c < dsp.settings.channels; c++) { + if(sinc_resampler[c]) delete sinc_resampler[c]; + sinc_resampler[c] = new SincResample(dsp.settings.frequency, frequency, 0.85, SincResample::QUALITY_HIGH); + } +} + +#endif diff --git a/nall/dsp/settings.hpp b/nall/dsp/settings.hpp new file mode 100755 index 00000000..3a8f24c6 --- /dev/null +++ b/nall/dsp/settings.hpp @@ -0,0 +1,50 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +void DSP::setChannels(unsigned channels) { + assert(channels > 0); + buffer.setChannels(channels); + output.setChannels(channels); + settings.channels = channels; +} + +void DSP::setPrecision(unsigned precision) { + settings.precision = precision; + settings.intensity = 1 << (settings.precision - 1); + settings.intensityInverse = 1.0 / settings.intensity; +} + +void DSP::setFrequency(real frequency) { + settings.frequency = frequency; + resampler->setFrequency(); +} + +void DSP::setVolume(real volume) { + settings.volume = volume; +} + +void DSP::setBalance(real balance) { + settings.balance = balance; +} + +void DSP::setResampler(ResampleEngine engine) { + if(resampler) delete resampler; + + switch(engine) { + case ResampleEngine::Nearest: resampler = new ResampleNearest(*this); return; + case ResampleEngine::Linear: resampler = new ResampleLinear (*this); return; + case ResampleEngine::Cosine: resampler = new ResampleCosine (*this); return; + case ResampleEngine::Cubic: resampler = new ResampleCubic (*this); return; + case ResampleEngine::Hermite: resampler = new ResampleHermite(*this); return; + case ResampleEngine::Average: resampler = new ResampleAverage(*this); return; + case ResampleEngine::Sinc: resampler = new ResampleSinc (*this); return; + } + + throw; +} + +void DSP::setResamplerFrequency(real frequency) { + resampler->frequency = frequency; + resampler->setFrequency(); +} + +#endif diff --git a/nall/endian.hpp b/nall/endian.hpp new file mode 100755 index 00000000..1f834b5b --- /dev/null +++ b/nall/endian.hpp @@ -0,0 +1,42 @@ +#ifndef NALL_ENDIAN_HPP +#define NALL_ENDIAN_HPP + +#include + +#if defined(ENDIAN_LSB) + //little-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201 + #define order_lsb2(a,b) a,b + #define order_lsb3(a,b,c) a,b,c + #define order_lsb4(a,b,c,d) a,b,c,d + #define order_lsb5(a,b,c,d,e) a,b,c,d,e + #define order_lsb6(a,b,c,d,e,f) a,b,c,d,e,f + #define order_lsb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g + #define order_lsb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h + #define order_msb2(a,b) b,a + #define order_msb3(a,b,c) c,b,a + #define order_msb4(a,b,c,d) d,c,b,a + #define order_msb5(a,b,c,d,e) e,d,c,b,a + #define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a + #define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a + #define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a +#elif defined(ENDIAN_MSB) + //big-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x01020304 + #define order_lsb2(a,b) b,a + #define order_lsb3(a,b,c) c,b,a + #define order_lsb4(a,b,c,d) d,c,b,a + #define order_lsb5(a,b,c,d,e) e,d,c,b,a + #define order_lsb6(a,b,c,d,e,f) f,e,d,c,b,a + #define order_lsb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a + #define order_lsb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a + #define order_msb2(a,b) a,b + #define order_msb3(a,b,c) a,b,c + #define order_msb4(a,b,c,d) a,b,c,d + #define order_msb5(a,b,c,d,e) a,b,c,d,e + #define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f + #define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g + #define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h +#else + #error "Unknown endian. Please specify in nall/intrinsics.hpp" +#endif + +#endif diff --git a/nall/file.hpp b/nall/file.hpp new file mode 100755 index 00000000..8447f3ab --- /dev/null +++ b/nall/file.hpp @@ -0,0 +1,285 @@ +#ifndef NALL_FILE_HPP +#define NALL_FILE_HPP + +#include +#include +#include +#include +#include + +namespace nall { + inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) { + #if !defined(_WIN32) + return fopen(utf8_filename, mode); + #else + return _wfopen(utf16_t(utf8_filename), utf16_t(mode)); + #endif + } + + class file { + public: + enum class mode : unsigned { read, write, readwrite, writeread }; + enum class index : unsigned { absolute, relative }; + enum class time : unsigned { create, modify, access }; + + static bool read(const string &filename, uint8_t *&data, unsigned &size) { + data = 0; + file fp; + if(fp.open(filename, mode::read) == false) return false; + size = fp.size(); + data = new uint8_t[size]; + fp.read(data, size); + fp.close(); + return true; + } + + static bool read(const string &filename, const uint8_t *&data, unsigned &size) { + return file::read(filename, (uint8_t*&)data, size); + } + + static bool write(const string &filename, const uint8_t *data, unsigned size) { + file fp; + if(fp.open(filename, mode::write) == false) return false; + fp.write(data, size); + fp.close(); + return true; + } + + uint8_t read() { + if(!fp) return 0xff; //file not open + if(file_mode == mode::write) return 0xff; //reads not permitted + if(file_offset >= file_size) return 0xff; //cannot read past end of file + buffer_sync(); + return buffer[(file_offset++) & buffer_mask]; + } + + uintmax_t readl(unsigned length = 1) { + uintmax_t data = 0; + for(int i = 0; i < length; i++) { + data |= (uintmax_t)read() << (i << 3); + } + return data; + } + + uintmax_t readm(unsigned length = 1) { + uintmax_t data = 0; + while(length--) { + data <<= 8; + data |= read(); + } + return data; + } + + void read(uint8_t *buffer, unsigned length) { + while(length--) *buffer++ = read(); + } + + void write(uint8_t data) { + if(!fp) return; //file not open + if(file_mode == mode::read) return; //writes not permitted + buffer_sync(); + buffer[(file_offset++) & buffer_mask] = data; + buffer_dirty = true; + if(file_offset > file_size) file_size = file_offset; + } + + void writel(uintmax_t data, unsigned length = 1) { + while(length--) { + write(data); + data >>= 8; + } + } + + void writem(uintmax_t data, unsigned length = 1) { + for(int i = length - 1; i >= 0; i--) { + write(data >> (i << 3)); + } + } + + void write(const uint8_t *buffer, unsigned length) { + while(length--) write(*buffer++); + } + + template void print(Args... args) { + string data(args...); + const char *p = data; + while(*p) write(*p++); + } + + void flush() { + buffer_flush(); + fflush(fp); + } + + void seek(int offset, index index_ = index::absolute) { + if(!fp) return; //file not open + buffer_flush(); + + uintmax_t req_offset = file_offset; + switch(index_) { + case index::absolute: req_offset = offset; break; + case index::relative: req_offset += offset; break; + } + + if(req_offset < 0) req_offset = 0; //cannot seek before start of file + if(req_offset > file_size) { + if(file_mode == mode::read) { //cannot seek past end of file + req_offset = file_size; + } else { //pad file to requested location + file_offset = file_size; + while(file_size < req_offset) write(0x00); + } + } + + file_offset = req_offset; + } + + int offset() { + if(!fp) return -1; //file not open + return file_offset; + } + + int size() { + if(!fp) return -1; //file not open + return file_size; + } + + bool truncate(unsigned size) { + if(!fp) return false; //file not open + #if !defined(_WIN32) + return ftruncate(fileno(fp), size) == 0; + #else + return _chsize(fileno(fp), size) == 0; + #endif + } + + bool end() { + if(!fp) return true; //file not open + return file_offset >= file_size; + } + + static bool exists(const string &filename) { + #if !defined(_WIN32) + struct stat64 data; + return stat64(filename, &data) == 0; + #else + struct __stat64 data; + return _wstat64(utf16_t(filename), &data) == 0; + #endif + } + + static uintmax_t size(const string &filename) { + #if !defined(_WIN32) + struct stat64 data; + stat64(filename, &data); + #else + struct __stat64 data; + _wstat64(utf16_t(filename), &data); + #endif + return S_ISREG(data.st_mode) ? data.st_size : 0u; + } + + static time_t timestamp(const string &filename, file::time mode = file::time::create) { + #if !defined(_WIN32) + struct stat64 data; + stat64(filename, &data); + #else + struct __stat64 data; + _wstat64(utf16_t(filename), &data); + #endif + switch(mode) { default: + case file::time::create: return data.st_ctime; + case file::time::modify: return data.st_mtime; + case file::time::access: return data.st_atime; + } + } + + bool open() { + return fp; + } + + bool open(const string &filename, mode mode_) { + if(fp) return false; + + switch(file_mode = mode_) { + #if !defined(_WIN32) + case mode::read: fp = fopen(filename, "rb" ); break; + case mode::write: fp = fopen(filename, "wb+"); break; //need read permission for buffering + case mode::readwrite: fp = fopen(filename, "rb+"); break; + case mode::writeread: fp = fopen(filename, "wb+"); break; + #else + case mode::read: fp = _wfopen(utf16_t(filename), L"rb" ); break; + case mode::write: fp = _wfopen(utf16_t(filename), L"wb+"); break; + case mode::readwrite: fp = _wfopen(utf16_t(filename), L"rb+"); break; + case mode::writeread: fp = _wfopen(utf16_t(filename), L"wb+"); break; + #endif + } + if(!fp) return false; + buffer_offset = -1; //invalidate buffer + file_offset = 0; + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + return true; + } + + void close() { + if(!fp) return; + buffer_flush(); + fclose(fp); + fp = 0; + } + + file() { + memset(buffer, 0, sizeof buffer); + buffer_offset = -1; + buffer_dirty = false; + fp = 0; + file_offset = 0; + file_size = 0; + file_mode = mode::read; + } + + ~file() { + close(); + } + + file& operator=(const file&) = delete; + file(const file&) = delete; + + private: + enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 }; + char buffer[buffer_size]; + int buffer_offset; + bool buffer_dirty; + FILE *fp; + unsigned file_offset; + unsigned file_size; + mode file_mode; + + void buffer_sync() { + if(!fp) return; //file not open + if(buffer_offset != (file_offset & ~buffer_mask)) { + buffer_flush(); + buffer_offset = file_offset & ~buffer_mask; + fseek(fp, buffer_offset, SEEK_SET); + unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); + if(length) unsigned unused = fread(buffer, 1, length, fp); + } + } + + void buffer_flush() { + if(!fp) return; //file not open + if(file_mode == mode::read) return; //buffer cannot be written to + if(buffer_offset < 0) return; //buffer unused + if(buffer_dirty == false) return; //buffer unmodified since read + fseek(fp, buffer_offset, SEEK_SET); + unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); + if(length) unsigned unused = fwrite(buffer, 1, length, fp); + buffer_offset = -1; //invalidate buffer + buffer_dirty = false; + } + }; +} + +#endif diff --git a/nall/filemap.hpp b/nall/filemap.hpp new file mode 100755 index 00000000..7eeac2b0 --- /dev/null +++ b/nall/filemap.hpp @@ -0,0 +1,212 @@ +#ifndef NALL_FILEMAP_HPP +#define NALL_FILEMAP_HPP + +#include +#include + +#include +#include +#if defined(_WIN32) + #include +#else + #include + #include + #include + #include + #include +#endif + +namespace nall { + class filemap { + public: + enum class mode : unsigned { read, write, readwrite, writeread }; + + bool open() const { return p_open(); } + bool open(const char *filename, mode mode_) { return p_open(filename, mode_); } + void close() { return p_close(); } + unsigned size() const { return p_size; } + uint8_t* data() { return p_handle; } + const uint8_t* data() const { return p_handle; } + filemap() : p_size(0), p_handle(0) { p_ctor(); } + filemap(const char *filename, mode mode_) : p_size(0), p_handle(0) { p_ctor(); p_open(filename, mode_); } + ~filemap() { p_dtor(); } + + private: + unsigned p_size; + uint8_t *p_handle; + + #if defined(_WIN32) + //============= + //MapViewOfFile + //============= + + HANDLE p_filehandle, p_maphandle; + + bool p_open() const { + return p_handle; + } + + bool p_open(const char *filename, mode mode_) { + if(file::exists(filename) && file::size(filename) == 0) { + p_handle = 0; + p_size = 0; + return true; + } + + int desired_access, creation_disposition, flprotect, map_access; + + switch(mode_) { + default: return false; + case mode::read: + desired_access = GENERIC_READ; + creation_disposition = OPEN_EXISTING; + flprotect = PAGE_READONLY; + map_access = FILE_MAP_READ; + break; + case mode::write: + //write access requires read access + desired_access = GENERIC_WRITE; + creation_disposition = CREATE_ALWAYS; + flprotect = PAGE_READWRITE; + map_access = FILE_MAP_ALL_ACCESS; + break; + case mode::readwrite: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = OPEN_EXISTING; + flprotect = PAGE_READWRITE; + map_access = FILE_MAP_ALL_ACCESS; + break; + case mode::writeread: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = CREATE_NEW; + flprotect = PAGE_READWRITE; + map_access = FILE_MAP_ALL_ACCESS; + break; + } + + p_filehandle = CreateFileW(utf16_t(filename), desired_access, FILE_SHARE_READ, NULL, + creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL); + if(p_filehandle == INVALID_HANDLE_VALUE) return false; + + p_size = GetFileSize(p_filehandle, NULL); + + p_maphandle = CreateFileMapping(p_filehandle, NULL, flprotect, 0, p_size, NULL); + if(p_maphandle == INVALID_HANDLE_VALUE) { + CloseHandle(p_filehandle); + p_filehandle = INVALID_HANDLE_VALUE; + return false; + } + + p_handle = (uint8_t*)MapViewOfFile(p_maphandle, map_access, 0, 0, p_size); + return p_handle; + } + + void p_close() { + if(p_handle) { + UnmapViewOfFile(p_handle); + p_handle = 0; + } + + if(p_maphandle != INVALID_HANDLE_VALUE) { + CloseHandle(p_maphandle); + p_maphandle = INVALID_HANDLE_VALUE; + } + + if(p_filehandle != INVALID_HANDLE_VALUE) { + CloseHandle(p_filehandle); + p_filehandle = INVALID_HANDLE_VALUE; + } + } + + void p_ctor() { + p_filehandle = INVALID_HANDLE_VALUE; + p_maphandle = INVALID_HANDLE_VALUE; + } + + void p_dtor() { + close(); + } + + #else + //==== + //mmap + //==== + + int p_fd; + + bool p_open() const { + return p_handle; + } + + bool p_open(const char *filename, mode mode_) { + if(file::exists(filename) && file::size(filename) == 0) { + p_handle = 0; + p_size = 0; + return true; + } + + int open_flags, mmap_flags; + + switch(mode_) { + default: return false; + case mode::read: + open_flags = O_RDONLY; + mmap_flags = PROT_READ; + break; + case mode::write: + open_flags = O_RDWR | O_CREAT; //mmap() requires read access + mmap_flags = PROT_WRITE; + break; + case mode::readwrite: + open_flags = O_RDWR; + mmap_flags = PROT_READ | PROT_WRITE; + break; + case mode::writeread: + open_flags = O_RDWR | O_CREAT; + mmap_flags = PROT_READ | PROT_WRITE; + break; + } + + p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if(p_fd < 0) return false; + + struct stat p_stat; + fstat(p_fd, &p_stat); + p_size = p_stat.st_size; + + p_handle = (uint8_t*)mmap(0, p_size, mmap_flags, MAP_SHARED, p_fd, 0); + if(p_handle == MAP_FAILED) { + p_handle = 0; + ::close(p_fd); + p_fd = -1; + return false; + } + + return p_handle; + } + + void p_close() { + if(p_handle) { + munmap(p_handle, p_size); + p_handle = 0; + } + + if(p_fd >= 0) { + ::close(p_fd); + p_fd = -1; + } + } + + void p_ctor() { + p_fd = -1; + } + + void p_dtor() { + p_close(); + } + + #endif + }; +} + +#endif diff --git a/nall/function.hpp b/nall/function.hpp new file mode 100755 index 00000000..ca574b8c --- /dev/null +++ b/nall/function.hpp @@ -0,0 +1,60 @@ +#ifndef NALL_FUNCTION_HPP +#define NALL_FUNCTION_HPP + +namespace nall { + template class function; + + template class function { + struct container { + virtual R operator()(P... p) const = 0; + virtual container* copy() const = 0; + virtual ~container() {} + } *callback; + + struct global : container { + R (*function)(P...); + R operator()(P... p) const { return function(std::forward

(p)...); } + container* copy() const { return new global(function); } + global(R (*function)(P...)) : function(function) {} + }; + + template struct member : container { + R (C::*function)(P...); + C *object; + R operator()(P... p) const { return (object->*function)(std::forward

(p)...); } + container* copy() const { return new member(function, object); } + member(R (C::*function)(P...), C *object) : function(function), object(object) {} + }; + + template struct lambda : container { + mutable L object; + R operator()(P... p) const { return object(std::forward

(p)...); } + container* copy() const { return new lambda(object); } + lambda(const L& object) : object(object) {} + }; + + public: + operator bool() const { return callback; } + R operator()(P... p) const { return (*callback)(std::forward

(p)...); } + void reset() { if(callback) { delete callback; callback = nullptr; } } + + function& operator=(const function &source) { + if(this != &source) { + if(callback) { delete callback; callback = nullptr; } + if(source.callback) callback = source.callback->copy(); + } + return *this; + } + + function(const function &source) : callback(nullptr) { operator=(source); } + function() : callback(nullptr) {} + function(void *function) : callback(nullptr) { if(function) callback = new global((R (*)(P...))function); } + function(R (*function)(P...)) { callback = new global(function); } + template function(R (C::*function)(P...), C *object) { callback = new member(function, object); } + template function(R (C::*function)(P...) const, C *object) { callback = new member((R (C::*)(P...))function, object); } + template function(const L& object) { callback = new lambda(object); } + ~function() { if(callback) delete callback; } + }; +} + +#endif diff --git a/nall/gameboy/cartridge.hpp b/nall/gameboy/cartridge.hpp new file mode 100755 index 00000000..19ff065d --- /dev/null +++ b/nall/gameboy/cartridge.hpp @@ -0,0 +1,116 @@ +#ifndef NALL_GAMEBOY_CARTRIDGE_HPP +#define NALL_GAMEBOY_CARTRIDGE_HPP + +namespace nall { + +class GameBoyCartridge { +public: + string markup; + inline GameBoyCartridge(uint8_t *data, unsigned size); + +//private: + struct Information { + string mapper; + bool ram; + bool battery; + bool rtc; + bool rumble; + + unsigned romsize; + unsigned ramsize; + } info; +}; + +GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) { + markup = ""; + if(romsize < 0x4000) return; + + info.mapper = "unknown"; + info.ram = false; + info.battery = false; + info.rtc = false; + info.rumble = false; + + info.romsize = 0; + info.ramsize = 0; + + unsigned base = romsize - 0x8000; + if(romdata[base + 0x0104] == 0xce && romdata[base + 0x0105] == 0xed + && romdata[base + 0x0106] == 0x66 && romdata[base + 0x0107] == 0x66 + && romdata[base + 0x0108] == 0xcc && romdata[base + 0x0109] == 0x0d + && romdata[base + 0x0147] >= 0x0b && romdata[base + 0x0147] <= 0x0d + ) { + //MMM01 stores header at bottom of image + //flip this around for consistency with all other mappers + uint8_t header[0x8000]; + memcpy(header, romdata + base, 0x8000); + memmove(romdata + 0x8000, romdata, romsize - 0x8000); + memcpy(romdata, header, 0x8000); + } + + switch(romdata[0x0147]) { + case 0x00: info.mapper = "none"; break; + case 0x01: info.mapper = "MBC1"; break; + case 0x02: info.mapper = "MBC1"; info.ram = true; break; + case 0x03: info.mapper = "MBC1"; info.ram = true; info.battery = true; break; + case 0x05: info.mapper = "MBC2"; info.ram = true; break; + case 0x06: info.mapper = "MBC2"; info.ram = true; info.battery = true; break; + case 0x08: info.mapper = "none"; info.ram = true; break; + case 0x09: info.mapper = "MBC0"; info.ram = true; info.battery = true; break; + case 0x0b: info.mapper = "MMM01"; break; + case 0x0c: info.mapper = "MMM01"; info.ram = true; break; + case 0x0d: info.mapper = "MMM01"; info.ram = true; info.battery = true; break; + case 0x0f: info.mapper = "MBC3"; info.rtc = true; info.battery = true; break; + case 0x10: info.mapper = "MBC3"; info.rtc = true; info.ram = true; info.battery = true; break; + case 0x11: info.mapper = "MBC3"; break; + case 0x12: info.mapper = "MBC3"; info.ram = true; break; + case 0x13: info.mapper = "MBC3"; info.ram = true; info.battery = true; break; + case 0x19: info.mapper = "MBC5"; break; + case 0x1a: info.mapper = "MBC5"; info.ram = true; break; + case 0x1b: info.mapper = "MBC5"; info.ram = true; info.battery = true; break; + case 0x1c: info.mapper = "MBC5"; info.rumble = true; break; + case 0x1d: info.mapper = "MBC5"; info.rumble = true; info.ram = true; break; + case 0x1e: info.mapper = "MBC5"; info.rumble = true; info.ram = true; info.battery = true; break; + case 0xfc: break; //Pocket Camera + case 0xfd: break; //Bandai TAMA5 + case 0xfe: info.mapper = "HuC3"; break; + case 0xff: info.mapper = "HuC1"; info.ram = true; info.battery = true; break; + } + + switch(romdata[0x0148]) { default: + case 0x00: info.romsize = 2 * 16 * 1024; break; + case 0x01: info.romsize = 4 * 16 * 1024; break; + case 0x02: info.romsize = 8 * 16 * 1024; break; + case 0x03: info.romsize = 16 * 16 * 1024; break; + case 0x04: info.romsize = 32 * 16 * 1024; break; + case 0x05: info.romsize = 64 * 16 * 1024; break; + case 0x06: info.romsize = 128 * 16 * 1024; break; + case 0x07: info.romsize = 256 * 16 * 1024; break; + case 0x52: info.romsize = 72 * 16 * 1024; break; + case 0x53: info.romsize = 80 * 16 * 1024; break; + case 0x54: info.romsize = 96 * 16 * 1024; break; + } + + switch(romdata[0x0149]) { default: + case 0x00: info.ramsize = 0 * 1024; break; + case 0x01: info.ramsize = 2 * 1024; break; + case 0x02: info.ramsize = 8 * 1024; break; + case 0x03: info.ramsize = 32 * 1024; break; + } + + if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit + + markup.append("cartridge mapper=", info.mapper); + if(info.rtc) markup.append(" rtc"); + if(info.rumble) markup.append(" rumble"); + markup.append("\n"); + + markup.append("\t" "rom size=", hex(romsize), "\n"); //TODO: trust/check info.romsize? + + if(info.ramsize > 0) + markup.append("\t" "ram size=", hex(info.ramsize), info.battery ? " non-volatile\n" : "\n"); +} + +} + +#endif diff --git a/nall/gzip.hpp b/nall/gzip.hpp new file mode 100755 index 00000000..8f5d206b --- /dev/null +++ b/nall/gzip.hpp @@ -0,0 +1,87 @@ +#ifndef NALL_GZIP_HPP +#define NALL_GZIP_HPP + +#include +#include + +namespace nall { + +struct gzip { + string filename; + uint8_t *data; + unsigned size; + + bool decompress(const string &filename); + bool decompress(const uint8_t *data, unsigned size); + + gzip(); + ~gzip(); +}; + +bool gzip::decompress(const string &filename) { + uint8_t *data; + unsigned size; + if(file::read(filename, data, size) == false) return false; + bool result = decompress(data, size); + delete[] data; + return result; +} + +bool gzip::decompress(const uint8_t *data, unsigned size) { + if(size < 18) return false; + if(data[0] != 0x1f) return false; + if(data[1] != 0x8b) return false; + unsigned cm = data[2]; + unsigned flg = data[3]; + unsigned mtime = data[4]; + mtime |= data[5] << 8; + mtime |= data[6] << 16; + mtime |= data[7] << 24; + unsigned xfl = data[8]; + unsigned os = data[9]; + unsigned p = 10; + unsigned isize = data[size - 4]; + isize |= data[size - 3] << 8; + isize |= data[size - 2] << 16; + isize |= data[size - 1] << 24; + filename = ""; + + if(flg & 0x04) { //FEXTRA + unsigned xlen = data[p + 0]; + xlen |= data[p + 1] << 8; + p += 2 + xlen; + } + + if(flg & 0x08) { //FNAME + char buffer[PATH_MAX]; + for(unsigned n = 0; n < PATH_MAX; n++, p++) { + buffer[n] = data[p]; + if(data[p] == 0) break; + } + if(data[p++]) return false; + filename = buffer; + } + + if(flg & 0x10) { //FCOMMENT + while(data[p++]); + } + + if(flg & 0x02) { //FHCRC + p += 2; + } + + this->size = isize; + this->data = new uint8_t[this->size]; + return inflate(this->data, this->size, data + p, size - p - 8); +} + +gzip::gzip() : data(nullptr) { +} + +gzip::~gzip() { + if(data) delete[] data; +} + +} + +#endif diff --git a/nall/http.hpp b/nall/http.hpp new file mode 100755 index 00000000..1b2eab4f --- /dev/null +++ b/nall/http.hpp @@ -0,0 +1,176 @@ +#ifndef NALL_HTTP_HPP +#define NALL_HTTP_HPP + +#if !defined(_WIN32) + #include + #include + #include + #include +#else + #include + #include + #include +#endif + +#include +#include + +namespace nall { + +struct http { + string hostname; + addrinfo *serverinfo; + int serversocket; + string header; + + inline void download(const string &path, uint8_t *&data, unsigned &size) { + data = 0; + size = 0; + + send({ + "GET ", path, " HTTP/1.1\r\n" + "Host: ", hostname, "\r\n" + "Connection: close\r\n" + "\r\n" + }); + + header = downloadHeader(); + downloadContent(data, size); + } + + inline bool connect(string host, unsigned port) { + hostname = host; + + addrinfo hints; + memset(&hints, 0, sizeof(addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + int status = getaddrinfo(hostname, string(port), &hints, &serverinfo); + if(status != 0) return false; + + serversocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol); + if(serversocket == -1) return false; + + int result = ::connect(serversocket, serverinfo->ai_addr, serverinfo->ai_addrlen); + if(result == -1) return false; + + return true; + } + + inline bool send(const string &data) { + return send((const uint8_t*)(const char*)data, data.length()); + } + + inline bool send(const uint8_t *data, unsigned size) { + while(size) { + int length = ::send(serversocket, (const char*)data, size, 0); + if(length == -1) return false; + data += length; + size -= length; + } + return true; + } + + inline string downloadHeader() { + string output; + do { + char buffer[2]; + int length = recv(serversocket, buffer, 1, 0); + if(length <= 0) return output; + buffer[1] = 0; + output.append(buffer); + } while(output.endswith("\r\n\r\n") == false); + return output; + } + + inline string downloadChunkLength() { + string output; + do { + char buffer[2]; + int length = recv(serversocket, buffer, 1, 0); + if(length <= 0) return output; + buffer[1] = 0; + output.append(buffer); + } while(output.endswith("\r\n") == false); + return output; + } + + inline void downloadContent(uint8_t *&data, unsigned &size) { + unsigned capacity = 0; + + if(header.iposition("\r\nTransfer-Encoding: chunked\r\n")) { + while(true) { + unsigned length = hex(downloadChunkLength()); + if(length == 0) break; + capacity += length; + data = (uint8_t*)realloc(data, capacity); + + char buffer[length]; + while(length) { + int packetlength = recv(serversocket, buffer, length, 0); + if(packetlength <= 0) break; + memcpy(data + size, buffer, packetlength); + size += packetlength; + length -= packetlength; + } + } + } else if(auto position = header.iposition("\r\nContent-Length: ")) { + unsigned length = decimal((const char*)header + position() + 16); + while(length) { + char buffer[256]; + int packetlength = recv(serversocket, buffer, min(256, length), 0); + if(packetlength <= 0) break; + capacity += packetlength; + data = (uint8_t*)realloc(data, capacity); + memcpy(data + size, buffer, packetlength); + size += packetlength; + length -= packetlength; + } + } else { + while(true) { + char buffer[256]; + int packetlength = recv(serversocket, buffer, 256, 0); + if(packetlength <= 0) break; + capacity += packetlength; + data = (uint8_t*)realloc(data, capacity); + memcpy(data + size, buffer, packetlength); + size += packetlength; + } + } + + data = (uint8_t*)realloc(data, capacity + 1); + data[capacity] = 0; + } + + inline void disconnect() { + close(serversocket); + freeaddrinfo(serverinfo); + serverinfo = 0; + serversocket = -1; + } + + #ifdef _WIN32 + inline int close(int sock) { + return closesocket(sock); + } + + inline http() { + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(sock == INVALID_SOCKET && WSAGetLastError() == WSANOTINITIALISED) { + WSADATA wsaData; + if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + WSACleanup(); + return; + } + } else { + close(sock); + } + } + #endif +}; + +} + +#endif diff --git a/nall/inflate.hpp b/nall/inflate.hpp new file mode 100755 index 00000000..cbbf6d29 --- /dev/null +++ b/nall/inflate.hpp @@ -0,0 +1,358 @@ +#ifndef NALL_INFLATE_HPP +#define NALL_INFLATE_HPP + +#include + +namespace nall { + +namespace puff { + inline int puff( + unsigned char *dest, unsigned long *destlen, + unsigned char *source, unsigned long *sourcelen + ); +} + +inline bool inflate( + uint8_t *target, unsigned targetLength, + const uint8_t *source, unsigned sourceLength +) { + unsigned long tl = targetLength, sl = sourceLength; + int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl); + return result == 0; +} + +namespace puff { + +//zlib/contrib/puff.c +//version 2.1* +//author: Mark Adler +//license: zlib +//ported by: byuu + +//* I have corrected a bug in fixed(), where it was accessing uninitialized +// memory: calling construct() with lencode prior to initializing lencode.count + +enum { + MAXBITS = 15, + MAXLCODES = 286, + MAXDCODES = 30, + FIXLCODES = 288, + MAXCODES = MAXLCODES + MAXDCODES, +}; + +struct state { + unsigned char *out; + unsigned long outlen; + unsigned long outcnt; + + unsigned char *in; + unsigned long inlen; + unsigned long incnt; + int bitbuf; + int bitcnt; + + jmp_buf env; +}; + +struct huffman { + short *count; + short *symbol; +}; + +inline int bits(state *s, int need) { + long val; + + val = s->bitbuf; + while(s->bitcnt < need) { + if(s->incnt == s->inlen) longjmp(s->env, 1); + val |= (long)(s->in[s->incnt++]) << s->bitcnt; + s->bitcnt += 8; + } + + s->bitbuf = (int)(val >> need); + s->bitcnt -= need; + + return (int)(val & ((1L << need) - 1)); +} + +inline int stored(state *s) { + unsigned len; + + s->bitbuf = 0; + s->bitcnt = 0; + + if(s->incnt + 4 > s->inlen) return 2; + len = s->in[s->incnt++]; + len |= s->in[s->incnt++] << 8; + if(s->in[s->incnt++] != (~len & 0xff) || + s->in[s->incnt++] != ((~len >> 8) & 0xff) + ) return 2; + + if(s->incnt + len > s->inlen) return 2; + if(s->out != 0) { + if(s->outcnt + len > s->outlen) return 1; + while(len--) s->out[s->outcnt++] = s->in[s->incnt++]; + } else { + s->outcnt += len; + s->incnt += len; + } + + return 0; +} + +inline int decode(state *s, huffman *h) { + int len, code, first, count, index, bitbuf, left; + short *next; + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while(true) { + while(left--) { + code |= bitbuf & 1; + bitbuf >>= 1; + count = *next++; + if(code - count < first) { + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS + 1) - len; + if(left == 0) break; + if(s->incnt == s->inlen) longjmp(s->env, 1); + bitbuf = s->in[s->incnt++]; + if(left > 8) left = 8; + } + + return -10; +} + +inline int construct(huffman *h, short *length, int n) { + int symbol, len, left; + short offs[MAXBITS + 1]; + + for(len = 0; len <= MAXBITS; len++) h->count[len] = 0; + for(symbol = 0; symbol < n; symbol++) h->count[length[symbol]]++; + if(h->count[0] == n) return 0; + + left = 1; + for(len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= h->count[len]; + if(left < 0) return left; + } + + offs[1] = 0; + for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len]; + + for(symbol = 0; symbol < n; symbol++) { + if(length[symbol] != 0) h->symbol[offs[length[symbol]]++] = symbol; + } + + return left; +} + +inline int codes(state *s, huffman *lencode, huffman *distcode) { + int symbol, len; + unsigned dist; + static const short lens[29] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 + }; + static const short lext[29] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 + }; + static const short dists[30] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + static const short dext[30] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13 + }; + + do { + symbol = decode(s, lencode); + if(symbol < 0) return symbol; + if(symbol < 256) { + if(s->out != 0) { + if(s->outcnt == s->outlen) return 1; + s->out[s->outcnt] = symbol; + } + s->outcnt++; + } else if(symbol > 256) { + symbol -= 257; + if(symbol >= 29) return -10; + len = lens[symbol] + bits(s, lext[symbol]); + + symbol = decode(s, distcode); + if(symbol < 0) return symbol; + dist = dists[symbol] + bits(s, dext[symbol]); + #ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR + if(dist > s->outcnt) return -11; + #endif + + if(s->out != 0) { + if(s->outcnt + len > s->outlen) return 1; + while(len--) { + s->out[s->outcnt] = + #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR + dist > s->outcnt ? 0 : + #endif + s->out[s->outcnt - dist]; + s->outcnt++; + } + } else { + s->outcnt += len; + } + } + } while(symbol != 256); + + return 0; +} + +inline int fixed(state *s) { + static int virgin = 1; + static short lencnt[MAXBITS + 1], lensym[FIXLCODES]; + static short distcnt[MAXBITS + 1], distsym[MAXDCODES]; + static huffman lencode, distcode; + + if(virgin) { + int symbol = 0; + short lengths[FIXLCODES]; + + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + for(; symbol < 144; symbol++) lengths[symbol] = 8; + for(; symbol < 256; symbol++) lengths[symbol] = 9; + for(; symbol < 280; symbol++) lengths[symbol] = 7; + for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8; + construct(&lencode, lengths, FIXLCODES); + + for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5; + construct(&distcode, lengths, MAXDCODES); + + virgin = 0; + } + + return codes(s, &lencode, &distcode); +} + +inline int dynamic(state *s) { + int nlen, ndist, ncode, index, err; + short lengths[MAXCODES]; + short lencnt[MAXBITS + 1], lensym[MAXLCODES]; + short distcnt[MAXBITS + 1], distsym[MAXDCODES]; + huffman lencode, distcode; + static const short order[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + nlen = bits(s, 5) + 257; + ndist = bits(s, 5) + 1; + ncode = bits(s, 4) + 4; + if(nlen > MAXLCODES || ndist > MAXDCODES) return -3; + + for(index = 0; index < ncode; index++) lengths[order[index]] = bits(s, 3); + for(; index < 19; index++) lengths[order[index]] = 0; + + err = construct(&lencode, lengths, 19); + if(err != 0) return -4; + + index = 0; + while(index < nlen + ndist) { + int symbol, len; + + symbol = decode(s, &lencode); + if(symbol < 16) { + lengths[index++] = symbol; + } else { + len = 0; + if(symbol == 16) { + if(index == 0) return -5; + len = lengths[index - 1]; + symbol = 3 + bits(s, 2); + } else if(symbol == 17) { + symbol = 3 + bits(s, 3); + } else { + symbol = 11 + bits(s, 7); + } + if(index + symbol > nlen + ndist) return -6; + while(symbol--) lengths[index++] = len; + } + } + + if(lengths[256] == 0) return -9; + + err = construct(&lencode, lengths, nlen); + if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) return -7; + + err = construct(&distcode, lengths + nlen, ndist); + if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) return -8; + + return codes(s, &lencode, &distcode); +} + +inline int puff( + unsigned char *dest, unsigned long *destlen, + unsigned char *source, unsigned long *sourcelen +) { + state s; + int last, type, err; + + s.out = dest; + s.outlen = *destlen; + s.outcnt = 0; + + s.in = source; + s.inlen = *sourcelen; + s.incnt = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + if(setjmp(s.env) != 0) { + err = 2; + } else { + do { + last = bits(&s, 1); + type = bits(&s, 2); + err = type == 0 ? stored(&s) + : type == 1 ? fixed(&s) + : type == 2 ? dynamic(&s) + : -1; + if(err != 0) break; + } while(!last); + } + + if(err <= 0) { + *destlen = s.outcnt; + *sourcelen = s.incnt; + } + + return err; +} + +} + +} + +#endif diff --git a/nall/input.hpp b/nall/input.hpp new file mode 100755 index 00000000..cd765393 --- /dev/null +++ b/nall/input.hpp @@ -0,0 +1,386 @@ +#ifndef NALL_INPUT_HPP +#define NALL_INPUT_HPP + +#include +#include +#include + +#include +#include + +namespace nall { + +struct Keyboard; +Keyboard& keyboard(unsigned = 0); + +static const char KeyboardScancodeName[][64] = { + "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", + "PrintScreen", "ScrollLock", "Pause", "Tilde", + "Num1", "Num2", "Num3", "Num4", "Num5", "Num6", "Num7", "Num8", "Num9", "Num0", + "Dash", "Equal", "Backspace", + "Insert", "Delete", "Home", "End", "PageUp", "PageDown", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "LeftBracket", "RightBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash", + "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "Keypad0", + "Point", "Enter", "Add", "Subtract", "Multiply", "Divide", + "NumLock", "CapsLock", + "Up", "Down", "Left", "Right", + "Tab", "Return", "Spacebar", "Menu", + "Shift", "Control", "Alt", "Super", +}; + +struct Keyboard { + const unsigned ID; + enum { Base = 1 }; + enum { Count = 8, Size = 128 }; + + enum Scancode { + Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + PrintScreen, ScrollLock, Pause, Tilde, + Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0, + Dash, Equal, Backspace, + Insert, Delete, Home, End, PageUp, PageDown, + A, B, C, D, E, F, G, H, I, J, K, L, M, + N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, + Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, + Point, Enter, Add, Subtract, Multiply, Divide, + NumLock, CapsLock, + Up, Down, Left, Right, + Tab, Return, Spacebar, Menu, + Shift, Control, Alt, Super, + Limit, + }; + + static signed numberDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(keyboard(i).belongsTo(scancode)) return i; + } + return -1; + } + + static signed keyDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(keyboard(i).isKey(scancode)) return scancode - keyboard(i).key(Escape); + } + return -1; + } + + static signed modifierDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(keyboard(i).isModifier(scancode)) return scancode - keyboard(i).key(Shift); + } + return -1; + } + + static bool isAnyKey(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(keyboard(i).isKey(scancode)) return true; + } + return false; + } + + static bool isAnyModifier(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(keyboard(i).isModifier(scancode)) return true; + } + return false; + } + + static uint16_t decode(const char *name) { + string s(name); + if(!strbegin(name, "KB")) return 0; + s.ltrim("KB"); + unsigned id = decimal(s); + auto pos = strpos(s, "::"); + if(!pos) return 0; + s = substr(s, pos() + 2); + for(unsigned i = 0; i < Limit; i++) { + if(s == KeyboardScancodeName[i]) return Base + Size * id + i; + } + return 0; + } + + string encode(uint16_t code) const { + unsigned index = 0; + for(unsigned i = 0; i < Count; i++) { + if(code >= Base + Size * i && code < Base + Size * (i + 1)) { + index = code - (Base + Size * i); + break; + } + } + return { "KB", ID, "::", KeyboardScancodeName[index] }; + } + + uint16_t operator[](Scancode code) const { return Base + ID * Size + code; } + uint16_t key(unsigned id) const { return Base + Size * ID + id; } + bool isKey(unsigned id) const { return id >= key(Escape) && id <= key(Menu); } + bool isModifier(unsigned id) const { return id >= key(Shift) && id <= key(Super); } + bool belongsTo(uint16_t scancode) const { return isKey(scancode) || isModifier(scancode); } + + Keyboard(unsigned ID_) : ID(ID_) {} +}; + +inline Keyboard& keyboard(unsigned id) { + static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7); + switch(id) { default: + case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3; + case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7; + } +} + +static const char MouseScancodeName[][64] = { + "Xaxis", "Yaxis", "Zaxis", + "Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7", +}; + +struct Mouse; +Mouse& mouse(unsigned = 0); + +struct Mouse { + const unsigned ID; + enum { Base = Keyboard::Base + Keyboard::Size * Keyboard::Count }; + enum { Count = 8, Size = 16 }; + enum { Axes = 3, Buttons = 8 }; + + enum Scancode { + Xaxis, Yaxis, Zaxis, + Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7, + Limit, + }; + + static signed numberDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(mouse(i).belongsTo(scancode)) return i; + } + return -1; + } + + static signed axisDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(mouse(i).isAxis(scancode)) return scancode - mouse(i).axis(0); + } + return -1; + } + + static signed buttonDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(mouse(i).isButton(scancode)) return scancode - mouse(i).button(0); + } + return -1; + } + + static bool isAnyAxis(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(mouse(i).isAxis(scancode)) return true; + } + return false; + } + + static bool isAnyButton(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(mouse(i).isButton(scancode)) return true; + } + return false; + } + + static uint16_t decode(const char *name) { + string s(name); + if(!strbegin(name, "MS")) return 0; + s.ltrim("MS"); + unsigned id = decimal(s); + auto pos = strpos(s, "::"); + if(!pos) return 0; + s = substr(s, pos() + 2); + for(unsigned i = 0; i < Limit; i++) { + if(s == MouseScancodeName[i]) return Base + Size * id + i; + } + return 0; + } + + string encode(uint16_t code) const { + unsigned index = 0; + for(unsigned i = 0; i < Count; i++) { + if(code >= Base + Size * i && code < Base + Size * (i + 1)) { + index = code - (Base + Size * i); + break; + } + } + return { "MS", ID, "::", MouseScancodeName[index] }; + } + + uint16_t operator[](Scancode code) const { return Base + ID * Size + code; } + uint16_t axis(unsigned id) const { return Base + Size * ID + Xaxis + id; } + uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; } + bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(2); } + bool isButton(unsigned id) const { return id >= button(0) && id <= button(7); } + bool belongsTo(uint16_t scancode) const { return isAxis(scancode) || isButton(scancode); } + + Mouse(unsigned ID_) : ID(ID_) {} +}; + +inline Mouse& mouse(unsigned id) { + static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7); + switch(id) { default: + case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3; + case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7; + } +} + +static const char JoypadScancodeName[][64] = { + "Hat0", "Hat1", "Hat2", "Hat3", "Hat4", "Hat5", "Hat6", "Hat7", + "Axis0", "Axis1", "Axis2", "Axis3", "Axis4", "Axis5", "Axis6", "Axis7", + "Axis8", "Axis9", "Axis10", "Axis11", "Axis12", "Axis13", "Axis14", "Axis15", + "Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7", + "Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15", + "Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23", + "Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31", +}; + +struct Joypad; +Joypad& joypad(unsigned = 0); + +struct Joypad { + const unsigned ID; + enum { Base = Mouse::Base + Mouse::Size * Mouse::Count }; + enum { Count = 8, Size = 64 }; + enum { Hats = 8, Axes = 16, Buttons = 32 }; + + enum Scancode { + Hat0, Hat1, Hat2, Hat3, Hat4, Hat5, Hat6, Hat7, + Axis0, Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7, + Axis8, Axis9, Axis10, Axis11, Axis12, Axis13, Axis14, Axis15, + Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7, + Button8, Button9, Button10, Button11, Button12, Button13, Button14, Button15, + Button16, Button17, Button18, Button19, Button20, Button21, Button22, Button23, + Button24, Button25, Button26, Button27, Button28, Button29, Button30, Button31, + Limit, + }; + + enum Hat { HatCenter = 0, HatUp = 1, HatRight = 2, HatDown = 4, HatLeft = 8 }; + + static signed numberDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(joypad(i).belongsTo(scancode)) return i; + } + return -1; + } + + static signed hatDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(joypad(i).isHat(scancode)) return scancode - joypad(i).hat(0); + } + return -1; + } + + static signed axisDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(joypad(i).isAxis(scancode)) return scancode - joypad(i).axis(0); + } + return -1; + } + + static signed buttonDecode(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(joypad(i).isButton(scancode)) return scancode - joypad(i).button(0); + } + return -1; + } + + static bool isAnyHat(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(joypad(i).isHat(scancode)) return true; + } + return false; + } + + static bool isAnyAxis(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(joypad(i).isAxis(scancode)) return true; + } + return false; + } + + static bool isAnyButton(uint16_t scancode) { + for(unsigned i = 0; i < Count; i++) { + if(joypad(i).isButton(scancode)) return true; + } + return false; + } + + static uint16_t decode(const char *name) { + string s(name); + if(!strbegin(name, "JP")) return 0; + s.ltrim("JP"); + unsigned id = decimal(s); + auto pos = strpos(s, "::"); + if(!pos) return 0; + s = substr(s, pos() + 2); + for(unsigned i = 0; i < Limit; i++) { + if(s == JoypadScancodeName[i]) return Base + Size * id + i; + } + return 0; + } + + string encode(uint16_t code) const { + unsigned index = 0; + for(unsigned i = 0; i < Count; i++) { + if(code >= Base + Size * i && code < Base + Size * (i + 1)) { + index = code - (Base + Size * i); + } + } + return { "JP", ID, "::", JoypadScancodeName[index] }; + } + + uint16_t operator[](Scancode code) const { return Base + ID * Size + code; } + uint16_t hat(unsigned id) const { return Base + Size * ID + Hat0 + id; } + uint16_t axis(unsigned id) const { return Base + Size * ID + Axis0 + id; } + uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; } + bool isHat(unsigned id) const { return id >= hat(0) && id <= hat(7); } + bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(15); } + bool isButton(unsigned id) const { return id >= button(0) && id <= button(31); } + bool belongsTo(uint16_t scancode) const { return isHat(scancode) || isAxis(scancode) || isButton(scancode); } + + Joypad(unsigned ID_) : ID(ID_) {} +}; + +inline Joypad& joypad(unsigned id) { + static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7); + switch(id) { default: + case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3; + case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7; + } +} + +struct Scancode { + enum { None = 0, Limit = Joypad::Base + Joypad::Size * Joypad::Count }; + + static uint16_t decode(const char *name) { + uint16_t code; + code = Keyboard::decode(name); + if(code) return code; + code = Mouse::decode(name); + if(code) return code; + code = Joypad::decode(name); + if(code) return code; + return None; + } + + static string encode(uint16_t code) { + for(unsigned i = 0; i < Keyboard::Count; i++) { + if(keyboard(i).belongsTo(code)) return keyboard(i).encode(code); + } + for(unsigned i = 0; i < Mouse::Count; i++) { + if(mouse(i).belongsTo(code)) return mouse(i).encode(code); + } + for(unsigned i = 0; i < Joypad::Count; i++) { + if(joypad(i).belongsTo(code)) return joypad(i).encode(code); + } + return "None"; + } +}; + +} + +#endif diff --git a/nall/intrinsics.hpp b/nall/intrinsics.hpp new file mode 100755 index 00000000..413ef593 --- /dev/null +++ b/nall/intrinsics.hpp @@ -0,0 +1,63 @@ +#ifndef NALL_INTRINSICS_HPP +#define NALL_INTRINSICS_HPP + +struct Intrinsics { + enum class Compiler : unsigned { GCC, VisualC, Unknown }; + enum class Platform : unsigned { X, OSX, Windows, Unknown }; + enum class Endian : unsigned { LSB, MSB, Unknown }; + + static inline Compiler compiler(); + static inline Platform platform(); + static inline Endian endian(); +}; + +/* Compiler detection */ + +#if defined(__GNUC__) + #define COMPILER_GCC + Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::GCC; } +#elif defined(_MSC_VER) + #define COMPILER_VISUALC + Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::VisualC; } +#else + #warning "unable to detect compiler" + #define COMPILER_UNKNOWN + Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::Unknown; } +#endif + +/* Platform detection */ + +#if defined(linux) || defined(__sun__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define PLATFORM_X + Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::X; } +#elif defined(__APPLE__) + #define PLATFORM_OSX + Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::OSX; } +#elif defined(_WIN32) + #define PLATFORM_WINDOWS + #define PLATFORM_WIN + Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Windows; } +#else + #warning "unable to detect platform" + #define PLATFORM_UNKNOWN + Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Unknown; } +#endif + +/* Endian detection */ + +#if defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64) + #define ENDIAN_LSB + #define ARCH_LSB + Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::LSB; } +#elif defined(__powerpc__) || defined(_M_PPC) || defined(__BIG_ENDIAN__) + #define ENDIAN_MSB + #define ARCH_MSB + Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::MSB; } +#else + #warning "unable to detect endian" + #define ENDIAN_UNKNOWN + #define ARCH_UNKNOWN + Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::Unknown; } +#endif + +#endif diff --git a/nall/ips.hpp b/nall/ips.hpp new file mode 100755 index 00000000..3071d038 --- /dev/null +++ b/nall/ips.hpp @@ -0,0 +1,110 @@ +#ifndef NALL_IPS_HPP +#define NALL_IPS_HPP + +#include +#include +#include + +namespace nall { + +struct ips { + inline bool apply(); + inline void source(const uint8_t *data, unsigned size); + inline void modify(const uint8_t *data, unsigned size); + inline bool source(const string &filename); + inline bool modify(const string &filename); + inline ips(); + inline ~ips(); + + uint8_t *data; + unsigned size; + const uint8_t *sourceData; + unsigned sourceSize; + const uint8_t *modifyData; + unsigned modifySize; +}; + +bool ips::apply() { + if(modifySize < 8) return false; + if(modifyData[0] != 'P') return false; + if(modifyData[1] != 'A') return false; + if(modifyData[2] != 'T') return false; + if(modifyData[3] != 'C') return false; + if(modifyData[4] != 'H') return false; + + if(data) delete[] data; + data = new uint8_t[16 * 1024 * 1024 + 65536](); //maximum size of IPS patch + single-tag padding + size = sourceSize; + memcpy(data, sourceData, sourceSize); + unsigned offset = 5; + + while(true) { + unsigned address, length; + + if(offset > modifySize - 3) break; + address = modifyData[offset++] << 16; + address |= modifyData[offset++] << 8; + address |= modifyData[offset++] << 0; + + if(address == 0x454f46) { //EOF + if(offset == modifySize) return true; + if(offset == modifySize - 3) { + size = modifyData[offset++] << 16; + size |= modifyData[offset++] << 8; + size |= modifyData[offset++] << 0; + return true; + } + } + + if(offset > modifySize - 2) break; + length = modifyData[offset++] << 8; + length |= modifyData[offset++] << 0; + + if(length) { //Copy + if(offset > modifySize - length) break; + while(length--) data[address++] = modifyData[offset++]; + } else { //RLE + if(offset > modifySize - 3) break; + length = modifyData[offset++] << 8; + length |= modifyData[offset++] << 0; + if(length == 0) break; //illegal + while(length--) data[address++] = modifyData[offset]; + offset++; + } + + size = max(size, address); + } + + delete[] data; + data = nullptr; + return false; +} + +void ips::source(const uint8_t *data, unsigned size) { + sourceData = data, sourceSize = size; +} + +void ips::modify(const uint8_t *data, unsigned size) { + modifyData = data, modifySize = size; +} + +bool ips::source(const string &filename) { + return file::read(filename, sourceData, sourceSize); +} + +bool ips::modify(const string &filename) { + return file::read(filename, modifyData, modifySize); +} + +ips::ips() : data(nullptr), sourceData(nullptr), modifyData(nullptr) { +} + +ips::~ips() { + if(data) delete[] data; + if(sourceData) delete[] sourceData; + if(modifyData) delete[] modifyData; +} + +} + +#endif diff --git a/nall/lzss.hpp b/nall/lzss.hpp new file mode 100755 index 00000000..fb3e0ba6 --- /dev/null +++ b/nall/lzss.hpp @@ -0,0 +1,165 @@ +#ifndef NALL_LZSS_HPP +#define NALL_LZSS_HPP + +#include +#include +#include +#include + +namespace nall { + +//19:5 pulldown +//8:1 marker: d7-d0 +//length: { 4 - 35 }, offset: { 1 - 0x80000 } +//4-byte file size header +//little-endian encoding +struct lzss { + inline void source(const uint8_t *data, unsigned size); + inline bool source(const string &filename); + inline unsigned size() const; + inline bool compress(const string &filename); + inline bool decompress(uint8_t *targetData, unsigned targetSize); + inline bool decompress(const string &filename); + +protected: + struct Node { + unsigned offset; + Node *next; + inline Node() : offset(0), next(nullptr) {} + inline ~Node() { if(next) delete next; } + } *tree[65536]; + + filemap sourceFile; + const uint8_t *sourceData; + unsigned sourceSize; + +public: + inline lzss() : sourceData(nullptr), sourceSize(0) {} +}; + +void lzss::source(const uint8_t *data, unsigned size) { + sourceData = data; + sourceSize = size; +} + +bool lzss::source(const string &filename) { + if(sourceFile.open(filename, filemap::mode::read) == false) return false; + sourceData = sourceFile.data(); + sourceSize = sourceFile.size(); + return true; +} + +unsigned lzss::size() const { + unsigned size = 0; + if(sourceSize < 4) return size; + for(unsigned n = 0; n < 32; n += 8) size |= sourceData[n >> 3] << n; + return size; +} + +bool lzss::compress(const string &filename) { + file targetFile; + if(targetFile.open(filename, file::mode::write) == false) return false; + + for(unsigned n = 0; n < 32; n += 8) targetFile.write(sourceSize >> n); + for(unsigned n = 0; n < 65536; n++) tree[n] = 0; + + uint8_t buffer[25]; + unsigned sourceOffset = 0; + + while(sourceOffset < sourceSize) { + uint8_t mask = 0x00; + unsigned bufferOffset = 1; + + for(unsigned iteration = 0; iteration < 8; iteration++) { + if(sourceOffset >= sourceSize) break; + + uint16_t symbol = sourceData[sourceOffset + 0]; + if(sourceOffset < sourceSize - 1) symbol |= sourceData[sourceOffset + 1] << 8; + Node *node = tree[symbol]; + unsigned maxLength = 0, maxOffset = 0; + + while(node) { + if(node->offset < sourceOffset - 0x80000) { + //out-of-range: all subsequent nodes will also be, so free up their memory + if(node->next) { delete node->next; node->next = 0; } + break; + } + + unsigned length = 0, x = sourceOffset, y = node->offset; + while(length < 35 && x < sourceSize && sourceData[x++] == sourceData[y++]) length++; + if(length > maxLength) maxLength = length, maxOffset = node->offset; + if(length == 35) break; + + node = node->next; + } + + //attach current symbol to top of tree for subsequent searches + node = new Node; + node->offset = sourceOffset; + node->next = tree[symbol]; + tree[symbol] = node; + + if(maxLength < 4) { + buffer[bufferOffset++] = sourceData[sourceOffset++]; + } else { + unsigned output = ((maxLength - 4) << 19) | (sourceOffset - 1 - maxOffset); + for(unsigned n = 0; n < 24; n += 8) buffer[bufferOffset++] = output >> n; + mask |= 0x80 >> iteration; + sourceOffset += maxLength; + } + } + + buffer[0] = mask; + targetFile.write(buffer, bufferOffset); + } + + sourceFile.close(); + targetFile.close(); + return true; +} + +bool lzss::decompress(uint8_t *targetData, unsigned targetSize) { + if(targetSize < size()) return false; + + unsigned sourceOffset = 4, targetOffset = 0; + while(sourceOffset < sourceSize) { + uint8_t mask = sourceData[sourceOffset++]; + + for(unsigned iteration = 0; iteration < 8; iteration++) { + if(sourceOffset >= sourceSize) break; + + if((mask & (0x80 >> iteration)) == 0) { + targetData[targetOffset++] = sourceData[sourceOffset++]; + } else { + unsigned code = 0; + for(unsigned n = 0; n < 24; n += 8) code |= sourceData[sourceOffset++] << n; + unsigned length = (code >> 19) + 4; + unsigned offset = targetOffset - 1 - (code & 0x7ffff); + while(length--) targetData[targetOffset++] = targetData[offset++]; + } + } + } +} + +bool lzss::decompress(const string &filename) { + if(sourceSize < 4) return false; + unsigned targetSize = size(); + + file fp; + if(fp.open(filename, file::mode::write) == false) return false; + fp.truncate(targetSize); + fp.close(); + + filemap targetFile; + if(targetFile.open(filename, filemap::mode::readwrite) == false) return false; + uint8_t *targetData = targetFile.data(); + + bool result = decompress(targetData, targetSize); + sourceFile.close(); + targetFile.close(); + return result; +} + +} + +#endif diff --git a/nall/moduloarray.hpp b/nall/moduloarray.hpp new file mode 100755 index 00000000..be549ae9 --- /dev/null +++ b/nall/moduloarray.hpp @@ -0,0 +1,40 @@ +#ifndef NALL_MODULO_HPP +#define NALL_MODULO_HPP + +#include + +namespace nall { + template class modulo_array { + public: + inline T operator[](int index) const { + return buffer[size + index]; + } + + inline T read(int index) const { + return buffer[size + index]; + } + + inline void write(unsigned index, const T value) { + buffer[index] = + buffer[index + size] = + buffer[index + size + size] = value; + } + + void serialize(serializer &s) { + s.array(buffer, size * 3); + } + + modulo_array() { + buffer = new T[size * 3](); + } + + ~modulo_array() { + delete[] buffer; + } + + private: + T *buffer; + }; +} + +#endif diff --git a/nall/platform.hpp b/nall/platform.hpp new file mode 100755 index 00000000..f3e4b3f5 --- /dev/null +++ b/nall/platform.hpp @@ -0,0 +1,142 @@ +#ifndef NALL_PLATFORM_HPP +#define NALL_PLATFORM_HPP + +#if defined(_WIN32) + //minimum version needed for _wstat64, etc + #undef __MSVCRT_VERSION__ + #define __MSVCRT_VERSION__ 0x0601 + #include +#endif + +//========================= +//standard platform headers +//========================= + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(_WIN32) + #include + #include + #include + #include + #undef interface + #define dllexport __declspec(dllexport) +#else + #include + #include + #define dllexport +#endif + +//================== +//warning supression +//================== + +//Visual C++ +#if defined(_MSC_VER) + //disable libc "deprecation" warnings + #pragma warning(disable:4996) +#endif + +//================ +//POSIX compliance +//================ + +#if defined(_MSC_VER) + #define PATH_MAX _MAX_PATH + #define va_copy(dest, src) ((dest) = (src)) +#endif + +#if defined(_WIN32) + #define getcwd _getcwd + #define ftruncate _chsize + #define mkdir(n, m) _wmkdir(nall::utf16_t(n)) + #define putenv _putenv + #define rmdir _rmdir + #define usleep(n) Sleep(n / 1000) + #define vsnprintf _vsnprintf +#endif + +//================ +//inline expansion +//================ + +#if defined(__GNUC__) + #define noinline __attribute__((noinline)) + #define inline inline + #define alwaysinline inline __attribute__((always_inline)) +#elif defined(_MSC_VER) + #define noinline __declspec(noinline) + #define inline inline + #define alwaysinline inline __forceinline +#else + #define noinline + #define inline inline + #define alwaysinline inline +#endif + +//========================= +//file system functionality +//========================= + +#if defined(_WIN32) + inline char* realpath(const char *filename, char *resolvedname) { + wchar_t fn[_MAX_PATH] = L""; + _wfullpath(fn, nall::utf16_t(filename), _MAX_PATH); + strcpy(resolvedname, nall::utf8_t(fn)); + for(unsigned n = 0; resolvedname[n]; n++) if(resolvedname[n] == '\\') resolvedname[n] = '/'; + return resolvedname; + } + + inline char* userpath(char *path) { + wchar_t fp[_MAX_PATH] = L""; + SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp); + strcpy(path, nall::utf8_t(fp)); + for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; + unsigned length = strlen(path); + if(path[length] != '/') strcpy(path + length, "/"); + return path; + } + + inline char* getcwd(char *path) { + wchar_t fp[_MAX_PATH] = L""; + _wgetcwd(fp, _MAX_PATH); + strcpy(path, nall::utf8_t(fp)); + for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; + unsigned length = strlen(path); + if(path[length] != '/') strcpy(path + length, "/"); + return path; + } +#else + //realpath() already exists + + inline char* userpath(char *path) { + *path = 0; + struct passwd *userinfo = getpwuid(getuid()); + if(userinfo) strcpy(path, userinfo->pw_dir); + unsigned length = strlen(path); + if(path[length] != '/') strcpy(path + length, "/"); + return path; + } + + inline char *getcwd(char *path) { + auto unused = getcwd(path, PATH_MAX); + unsigned length = strlen(path); + if(path[length] != '/') strcpy(path + length, "/"); + return path; + } +#endif + +#endif + diff --git a/nall/png.hpp b/nall/png.hpp new file mode 100755 index 00000000..a39c85c5 --- /dev/null +++ b/nall/png.hpp @@ -0,0 +1,426 @@ +#ifndef NALL_PNG_HPP +#define NALL_PNG_HPP + +//PNG image decoder +//author: byuu + +#include +#include + +namespace nall { + +struct png { + uint32_t *data; + unsigned size; + + struct Info { + unsigned width; + unsigned height; + unsigned bitDepth; + unsigned colorType; + unsigned compressionMethod; + unsigned filterType; + unsigned interlaceMethod; + + unsigned bytesPerPixel; + unsigned pitch; + + uint8_t palette[256][3]; + } info; + + uint8_t *rawData; + unsigned rawSize; + + inline bool decode(const string &filename); + inline bool decode(const uint8_t *sourceData, unsigned sourceSize); + inline void transform(); + inline void alphaTransform(uint32_t rgb = 0xffffff); + inline png(); + inline ~png(); + +protected: + enum class FourCC : unsigned { + IHDR = 0x49484452, + PLTE = 0x504c5445, + IDAT = 0x49444154, + IEND = 0x49454e44, + }; + + unsigned bitpos; + + inline unsigned interlace(unsigned pass, unsigned index); + inline unsigned inflateSize(); + inline bool deinterlace(const uint8_t *&inputData, unsigned pass); + inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height); + inline unsigned read(const uint8_t *data, unsigned length); + inline unsigned decode(const uint8_t *&data); + inline unsigned readbits(const uint8_t *&data); + inline unsigned scale(unsigned n); +}; + +bool png::decode(const string &filename) { + uint8_t *data; + unsigned size; + if(file::read(filename, data, size) == false) return false; + bool result = decode(data, size); + delete[] data; + return result; +} + +bool png::decode(const uint8_t *sourceData, unsigned sourceSize) { + if(sourceSize < 8) return false; + if(read(sourceData + 0, 4) != 0x89504e47) return false; + if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false; + + uint8_t *compressedData = 0; + unsigned compressedSize = 0; + + unsigned offset = 8; + while(offset < sourceSize) { + unsigned length = read(sourceData + offset + 0, 4); + unsigned fourCC = read(sourceData + offset + 4, 4); + unsigned checksum = read(sourceData + offset + 8 + length, 4); + + if(fourCC == (unsigned)FourCC::IHDR) { + info.width = read(sourceData + offset + 8, 4); + info.height = read(sourceData + offset + 12, 4); + info.bitDepth = read(sourceData + offset + 16, 1); + info.colorType = read(sourceData + offset + 17, 1); + info.compressionMethod = read(sourceData + offset + 18, 1); + info.filterType = read(sourceData + offset + 19, 1); + info.interlaceMethod = read(sourceData + offset + 20, 1); + + if(info.bitDepth == 0 || info.bitDepth > 16) return false; + if(info.bitDepth & (info.bitDepth - 1)) return false; //not a power of two + if(info.compressionMethod != 0) return false; + if(info.filterType != 0) return false; + if(info.interlaceMethod != 0 && info.interlaceMethod != 1) return false; + + switch(info.colorType) { + case 0: info.bytesPerPixel = info.bitDepth * 1; break; //L + case 2: info.bytesPerPixel = info.bitDepth * 3; break; //R,G,B + case 3: info.bytesPerPixel = info.bitDepth * 1; break; //P + case 4: info.bytesPerPixel = info.bitDepth * 2; break; //L,A + case 6: info.bytesPerPixel = info.bitDepth * 4; break; //R,G,B,A + default: return false; + } + + if(info.colorType == 2 || info.colorType == 4 || info.colorType == 6) + if(info.bitDepth != 8 && info.bitDepth != 16) return false; + if(info.colorType == 3 && info.bitDepth == 16) return false; + + info.bytesPerPixel = (info.bytesPerPixel + 7) / 8; + info.pitch = (int)info.width * info.bytesPerPixel; + } + + if(fourCC == (unsigned)FourCC::PLTE) { + if(length % 3) return false; + for(unsigned n = 0, p = offset + 8; n < length / 3; n++) { + info.palette[n][0] = sourceData[p++]; + info.palette[n][1] = sourceData[p++]; + info.palette[n][2] = sourceData[p++]; + } + } + + if(fourCC == (unsigned)FourCC::IDAT) { + compressedData = (uint8_t*)realloc(compressedData, compressedSize + length); + memcpy(compressedData + compressedSize, sourceData + offset + 8, length); + compressedSize += length; + } + + if(fourCC == (unsigned)FourCC::IEND) { + break; + } + + offset += 4 + 4 + length + 4; + } + + unsigned interlacedSize = inflateSize(); + uint8_t *interlacedData = new uint8_t[interlacedSize]; + + bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6); + delete[] compressedData; + + if(result == false) { + delete[] interlacedData; + return false; + } + + rawSize = info.width * info.height * info.bytesPerPixel; + rawData = new uint8_t[rawSize]; + + if(info.interlaceMethod == 0) { + if(filter(rawData, interlacedData, info.width, info.height) == false) { + delete[] interlacedData; + delete[] rawData; + rawData = 0; + return false; + } + } else { + const uint8_t *passData = interlacedData; + for(unsigned pass = 0; pass < 7; pass++) { + if(deinterlace(passData, pass) == false) { + delete[] interlacedData; + delete[] rawData; + rawData = 0; + return false; + } + } + } + + delete[] interlacedData; + return true; +} + +unsigned png::interlace(unsigned pass, unsigned index) { + static const unsigned data[7][4] = { + //x-distance, y-distance, x-origin, y-origin + { 8, 8, 0, 0 }, + { 8, 8, 4, 0 }, + { 4, 8, 0, 4 }, + { 4, 4, 2, 0 }, + { 2, 4, 0, 2 }, + { 2, 2, 1, 0 }, + { 1, 2, 0, 1 }, + }; + return data[pass][index]; +} + +unsigned png::inflateSize() { + if(info.interlaceMethod == 0) { + return info.width * info.height * info.bytesPerPixel + info.height; + } + + unsigned size = 0; + for(unsigned pass = 0; pass < 7; pass++) { + unsigned xd = interlace(pass, 0), yd = interlace(pass, 1); + unsigned xo = interlace(pass, 2), yo = interlace(pass, 3); + unsigned width = (info.width + (xd - xo - 1)) / xd; + unsigned height = (info.height + (yd - yo - 1)) / yd; + if(width == 0 || height == 0) continue; + size += width * height * info.bytesPerPixel + height; + } + return size; +} + +bool png::deinterlace(const uint8_t *&inputData, unsigned pass) { + unsigned xd = interlace(pass, 0), yd = interlace(pass, 1); + unsigned xo = interlace(pass, 2), yo = interlace(pass, 3); + unsigned width = (info.width + (xd - xo - 1)) / xd; + unsigned height = (info.height + (yd - yo - 1)) / yd; + if(width == 0 || height == 0) return true; + + unsigned outputSize = width * height * info.bytesPerPixel; + uint8_t *outputData = new uint8_t[outputSize]; + bool result = filter(outputData, inputData, width, height); + + const uint8_t *rd = outputData; + for(unsigned y = yo; y < info.height; y += yd) { + uint8_t *wr = rawData + y * info.pitch; + for(unsigned x = xo; x < info.width; x += xd) { + for(unsigned b = 0; b < info.bytesPerPixel; b++) { + wr[x * info.bytesPerPixel + b] = *rd++; + } + } + } + + inputData += outputSize + height; + delete[] outputData; + return result; +} + +bool png::filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height) { + uint8_t *wr = outputData; + const uint8_t *rd = inputData; + int bpp = info.bytesPerPixel, pitch = width * bpp; + for(int y = 0; y < height; y++) { + uint8_t filter = *rd++; + + switch(filter) { + case 0x00: //None + for(int x = 0; x < pitch; x++) { + wr[x] = rd[x]; + } + break; + + case 0x01: //Subtract + for(int x = 0; x < pitch; x++) { + wr[x] = rd[x] + (x - bpp < 0 ? 0 : wr[x - bpp]); + } + break; + + case 0x02: //Above + for(int x = 0; x < pitch; x++) { + wr[x] = rd[x] + (y - 1 < 0 ? 0 : wr[x - pitch]); + } + break; + + case 0x03: //Average + for(int x = 0; x < pitch; x++) { + short a = x - bpp < 0 ? 0 : wr[x - bpp]; + short b = y - 1 < 0 ? 0 : wr[x - pitch]; + + wr[x] = rd[x] + (uint8_t)((a + b) / 2); + } + break; + + case 0x04: //Paeth + for(int x = 0; x < pitch; x++) { + short a = x - bpp < 0 ? 0 : wr[x - bpp]; + short b = y - 1 < 0 ? 0 : wr[x - pitch]; + short c = x - bpp < 0 || y - 1 < 0 ? 0 : wr[x - pitch - bpp]; + + short p = a + b - c; + short pa = p > a ? p - a : a - p; + short pb = p > b ? p - b : b - p; + short pc = p > c ? p - c : c - p; + + uint8_t paeth = (uint8_t)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c); + + wr[x] = rd[x] + paeth; + } + break; + + default: //Invalid + return false; + } + + rd += pitch; + wr += pitch; + } + + return true; +} + +unsigned png::read(const uint8_t *data, unsigned length) { + unsigned result = 0; + while(length--) result = (result << 8) | (*data++); + return result; +} + +unsigned png::decode(const uint8_t *&data) { + unsigned p, r, g, b, a; + + switch(info.colorType) { + case 0: //L + r = g = b = scale(readbits(data)); + a = 0xff; + break; + case 2: //R,G,B + r = scale(readbits(data)); + g = scale(readbits(data)); + b = scale(readbits(data)); + a = 0xff; + break; + case 3: //P + p = readbits(data); + r = info.palette[p][0]; + g = info.palette[p][1]; + b = info.palette[p][2]; + a = 0xff; + break; + case 4: //L,A + r = g = b = scale(readbits(data)); + a = scale(readbits(data)); + break; + case 6: //R,G,B,A + r = scale(readbits(data)); + g = scale(readbits(data)); + b = scale(readbits(data)); + a = scale(readbits(data)); + break; + } + + return (a << 24) | (r << 16) | (g << 8) | (b << 0); +} + +unsigned png::readbits(const uint8_t *&data) { + unsigned result = 0; + switch(info.bitDepth) { + case 1: + result = (*data >> bitpos) & 1; + bitpos++; + if(bitpos == 8) { data++; bitpos = 0; } + break; + case 2: + result = (*data >> bitpos) & 3; + bitpos += 2; + if(bitpos == 8) { data++; bitpos = 0; } + break; + case 4: + result = (*data >> bitpos) & 15; + bitpos += 4; + if(bitpos == 8) { data++; bitpos = 0; } + break; + case 8: + result = *data++; + break; + case 16: + result = (data[0] << 8) | (data[1] << 0); + data += 2; + break; + } + return result; +} + +unsigned png::scale(unsigned n) { + switch(info.bitDepth) { + case 1: return n ? 0xff : 0x00; + case 2: return n * 0x55; + case 4: return n * 0x11; + case 8: return n; + case 16: return n >> 8; + } + return 0; +} + +void png::transform() { + if(data) delete[] data; + data = new uint32_t[info.width * info.height]; + + bitpos = 0; + const uint8_t *rd = rawData; + for(unsigned y = 0; y < info.height; y++) { + uint32_t *wr = data + y * info.width; + for(unsigned x = 0; x < info.width; x++) { + wr[x] = decode(rd); + } + } +} + +void png::alphaTransform(uint32_t rgb) { + transform(); + + uint8_t ir = rgb >> 16; + uint8_t ig = rgb >> 8; + uint8_t ib = rgb >> 0; + + uint32_t *p = data; + for(unsigned y = 0; y < info.height; y++) { + for(unsigned x = 0; x < info.width; x++) { + uint32_t pixel = *p; + uint8_t a = pixel >> 24; + uint8_t r = pixel >> 16; + uint8_t g = pixel >> 8; + uint8_t b = pixel >> 0; + + r = (r * a) + (ir * (255 - a)) >> 8; + g = (g * a) + (ig * (255 - a)) >> 8; + b = (b * a) + (ib * (255 - a)) >> 8; + + *p++ = (255 << 24) | (r << 16) | (g << 8) | (b << 0); + } + } +} + +png::png() : data(nullptr), rawData(nullptr) { +} + +png::~png() { + if(data) delete[] data; + if(rawData) delete[] rawData; +} + +} + +#endif diff --git a/nall/priorityqueue.hpp b/nall/priorityqueue.hpp new file mode 100755 index 00000000..443eac21 --- /dev/null +++ b/nall/priorityqueue.hpp @@ -0,0 +1,109 @@ +#ifndef NALL_PRIORITYQUEUE_HPP +#define NALL_PRIORITYQUEUE_HPP + +#include +#include +#include +#include + +namespace nall { + template void priority_queue_nocallback(type_t) {} + + //priority queue implementation using binary min-heap array; + //does not require normalize() function. + //O(1) find (tick) + //O(log n) append (enqueue) + //O(log n) remove (dequeue) + template class priority_queue { + public: + inline void tick(unsigned ticks) { + basecounter += ticks; + while(heapsize && gte(basecounter, heap[0].counter)) callback(dequeue()); + } + + //counter is relative to current time (eg enqueue(64, ...) fires in 64 ticks); + //counter cannot exceed std::numeric_limits::max() >> 1. + void enqueue(unsigned counter, type_t event) { + unsigned child = heapsize++; + counter += basecounter; + + while(child) { + unsigned parent = (child - 1) >> 1; + if(gte(counter, heap[parent].counter)) break; + + heap[child].counter = heap[parent].counter; + heap[child].event = heap[parent].event; + child = parent; + } + + heap[child].counter = counter; + heap[child].event = event; + } + + type_t dequeue() { + type_t event(heap[0].event); + unsigned parent = 0; + unsigned counter = heap[--heapsize].counter; + + while(true) { + unsigned child = (parent << 1) + 1; + if(child >= heapsize) break; + if(child + 1 < heapsize && gte(heap[child].counter, heap[child + 1].counter)) child++; + if(gte(heap[child].counter, counter)) break; + + heap[parent].counter = heap[child].counter; + heap[parent].event = heap[child].event; + parent = child; + } + + heap[parent].counter = counter; + heap[parent].event = heap[heapsize].event; + return event; + } + + void reset() { + basecounter = 0; + heapsize = 0; + } + + void serialize(serializer &s) { + s.integer(basecounter); + s.integer(heapsize); + for(unsigned n = 0; n < heapcapacity; n++) { + s.integer(heap[n].counter); + s.integer(heap[n].event); + } + } + + priority_queue(unsigned size, function callback_ = &priority_queue_nocallback) + : callback(callback_) { + heap = new heap_t[size]; + heapcapacity = size; + reset(); + } + + ~priority_queue() { + delete[] heap; + } + + priority_queue& operator=(const priority_queue&) = delete; + priority_queue(const priority_queue&) = delete; + + private: + function callback; + unsigned basecounter; + unsigned heapsize; + unsigned heapcapacity; + struct heap_t { + unsigned counter; + type_t event; + } *heap; + + //return true if x is greater than or equal to y + inline bool gte(unsigned x, unsigned y) { + return x - y < (std::numeric_limits::max() >> 1); + } + }; +} + +#endif diff --git a/nall/property.hpp b/nall/property.hpp new file mode 100755 index 00000000..665afcad --- /dev/null +++ b/nall/property.hpp @@ -0,0 +1,91 @@ +#ifndef NALL_PROPERTY_HPP +#define NALL_PROPERTY_HPP + +//nall::property implements ownership semantics into container classes +//example: property::readonly implies that only owner has full +//access to type; and all other code has readonly access. +// +//this code relies on extended friend semantics from C++0x to work, as it +//declares a friend class via a template paramter. it also exploits a bug in +//G++ 4.x to work even in C++98 mode. +// +//if compiling elsewhere, simply remove the friend class and private semantics + +//property can be used either of two ways: +//struct foo { +// property::readonly x; +// property::readwrite y; +//}; +//-or- +//struct foo : property { +// readonly x; +// readwrite y; +//}; + +//return types are const T& (byref) instead of T (byval) to avoid major speed +//penalties for objects with expensive copy constructors + +//operator-> provides access to underlying object type: +//readonly foo; +//foo->bar(); +//... will call Object::bar(); + +//operator='s reference is constant so as to avoid leaking a reference handle +//that could bypass access restrictions + +//both constant and non-constant operators are provided, though it may be +//necessary to cast first, for instance: +//struct foo : property { readonly bar; } object; +//int main() { int value = const_cast(object); } + +//writeonly is useful for objects that have non-const reads, but const writes. +//however, to avoid leaking handles, the interface is very restricted. the only +//way to write is via operator=, which requires conversion via eg copy +//constructor. example: +//struct foo { +// foo(bool value) { ... } +//}; +//writeonly bar; +//bar = true; + +namespace nall { + template struct property { + template struct traits { typedef T type; }; + + template struct readonly { + const T* operator->() const { return &value; } + const T& operator()() const { return value; } + operator const T&() const { return value; } + private: + T* operator->() { return &value; } + operator T&() { return value; } + const T& operator=(const T& value_) { return value = value_; } + T value; + friend class traits::type; + }; + + template struct writeonly { + void operator=(const T& value_) { value = value_; } + private: + const T* operator->() const { return &value; } + const T& operator()() const { return value; } + operator const T&() const { return value; } + T* operator->() { return &value; } + operator T&() { return value; } + T value; + friend class traits::type; + }; + + template struct readwrite { + const T* operator->() const { return &value; } + const T& operator()() const { return value; } + operator const T&() const { return value; } + T* operator->() { return &value; } + operator T&() { return value; } + const T& operator=(const T& value_) { return value = value_; } + T value; + }; + }; +} + +#endif diff --git a/nall/public_cast.hpp b/nall/public_cast.hpp new file mode 100755 index 00000000..331800e1 --- /dev/null +++ b/nall/public_cast.hpp @@ -0,0 +1,32 @@ +#ifndef NALL_PUBLIC_CAST_HPP +#define NALL_PUBLIC_CAST_HPP + +//this is a proof-of-concept-*only* C++ access-privilege elevation exploit. +//this code is 100% legal C++, per C++98 section 14.7.2 paragraph 8: +//"access checking rules do not apply to names in explicit instantiations." +//usage example: + +//struct N { typedef void (Class::*)(); }; +//template class public_cast; +//(class.*public_cast::value); + +//Class::Reference may be public, protected or private +//Class::Reference may be a function, object or variable + +namespace nall { + template struct public_cast; + + template struct public_cast { + static typename T::type value; + }; + + template typename T::type public_cast::value; + + template struct public_cast { + static typename T::type value; + }; + + template typename T::type public_cast::value = public_cast::value = P; +} + +#endif diff --git a/nall/random.hpp b/nall/random.hpp new file mode 100755 index 00000000..409c4561 --- /dev/null +++ b/nall/random.hpp @@ -0,0 +1,28 @@ +#ifndef NALL_RANDOM_HPP +#define NALL_RANDOM_HPP + +namespace nall { + //pseudo-random number generator + inline unsigned prng() { + static unsigned n = 0; + return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320); + } + + struct random_lfsr { + inline void seed(unsigned seed__) { + seed_ = seed__; + } + + inline unsigned operator()() { + return seed_ = (seed_ >> 1) ^ (((seed_ & 1) - 1) & 0xedb88320); + } + + random_lfsr() : seed_(0) { + } + + private: + unsigned seed_; + }; +} + +#endif diff --git a/nall/reference_array.hpp b/nall/reference_array.hpp new file mode 100755 index 00000000..7c915090 --- /dev/null +++ b/nall/reference_array.hpp @@ -0,0 +1,142 @@ +#ifndef NALL_REFERENCE_ARRAY_HPP +#define NALL_REFERENCE_ARRAY_HPP + +#include +#include +#include + +namespace nall { + template struct reference_array { + struct exception_out_of_bounds{}; + + protected: + typedef typename std::remove_reference::type type_t; + type_t **pool; + unsigned poolsize, buffersize; + + public: + unsigned size() const { return buffersize; } + unsigned capacity() const { return poolsize; } + + void reset() { + if(pool) free(pool); + pool = nullptr; + poolsize = 0; + buffersize = 0; + } + + void reserve(unsigned newsize) { + if(newsize == poolsize) return; + + pool = (type_t**)realloc(pool, sizeof(type_t*) * newsize); + poolsize = newsize; + buffersize = min(buffersize, newsize); + } + + void resize(unsigned newsize) { + if(newsize > poolsize) reserve(bit::round(newsize)); + buffersize = newsize; + } + + template + bool append(type_t& data, Args&&... args) { + bool result = append(data); + append(std::forward(args)...); + return result; + } + + bool append(type_t& data) { + for(unsigned index = 0; index < buffersize; index++) { + if(pool[index] == &data) return false; + } + + unsigned index = buffersize++; + if(index >= poolsize) resize(index + 1); + pool[index] = &data; + return true; + } + + bool remove(type_t& data) { + for(unsigned index = 0; index < buffersize; index++) { + if(pool[index] == &data) { + for(unsigned i = index; i < buffersize - 1; i++) pool[i] = pool[i + 1]; + resize(buffersize - 1); + return true; + } + } + return false; + } + + template reference_array(Args&... args) : pool(nullptr), poolsize(0), buffersize(0) { + construct(args...); + } + + ~reference_array() { + reset(); + } + + reference_array& operator=(const reference_array &source) { + if(pool) free(pool); + buffersize = source.buffersize; + poolsize = source.poolsize; + pool = (type_t**)malloc(sizeof(type_t*) * poolsize); + memcpy(pool, source.pool, sizeof(type_t*) * buffersize); + return *this; + } + + reference_array& operator=(const reference_array &&source) { + if(pool) free(pool); + pool = source.pool; + poolsize = source.poolsize; + buffersize = source.buffersize; + source.pool = nullptr; + source.reset(); + return *this; + } + + inline type_t& operator[](unsigned index) { + if(index >= buffersize) throw exception_out_of_bounds(); + return *pool[index]; + } + + inline type_t& operator[](unsigned index) const { + if(index >= buffersize) throw exception_out_of_bounds(); + return *pool[index]; + } + + //iteration + struct iterator { + bool operator!=(const iterator &source) const { return index != source.index; } + type_t& operator*() { return array.operator[](index); } + iterator& operator++() { index++; return *this; } + iterator(const reference_array &array, unsigned index) : array(array), index(index) {} + private: + const reference_array &array; + unsigned index; + }; + + iterator begin() { return iterator(*this, 0); } + iterator end() { return iterator(*this, buffersize); } + const iterator begin() const { return iterator(*this, 0); } + const iterator end() const { return iterator(*this, buffersize); } + + private: + void construct() { + } + + void construct(const reference_array &source) { + operator=(source); + } + + void construct(const reference_array &&source) { + operator=(std::move(source)); + } + + template void construct(T data, Args&... args) { + append(data); + construct(args...); + } + }; +} + +#endif diff --git a/nall/resource.hpp b/nall/resource.hpp new file mode 100755 index 00000000..f8fd5153 --- /dev/null +++ b/nall/resource.hpp @@ -0,0 +1,61 @@ +#ifndef NALL_RESOURCE_HPP +#define NALL_RESOURCE_HPP + +#include +#include + +namespace nall { + +struct resource { + //create resource with "zip -9 resource.zip resource" + static bool encode(const char *outputFilename, const char *inputFilename) { + file fp; + if(fp.open(inputFilename, file::mode::read) == false) return false; + unsigned size = fp.size(); + uint8_t *data = new uint8_t[size]; + fp.read(data, size); + fp.close(); + + fp.open(outputFilename, file::mode::write); + fp.print("static const uint8_t data[", size, "] = {\n"); + uint8_t *p = data; + while(size) { + fp.print(" "); + for(unsigned n = 0; n < 32 && size; n++, size--) { + fp.print((unsigned)*p++, ","); + } + fp.print("\n"); + } + fp.print("};\n"); + fp.close(); + + delete[] data; + } + + uint8_t *data; + unsigned size; + + //extract first file from ZIP archive + bool decode(const uint8_t *cdata, unsigned csize) { + if(data) delete[] data; + + zip archive; + if(archive.open(cdata, csize) == false) return false; + if(archive.file.size() == 0) return false; + bool result = archive.extract(archive.file[0], data, size); + archive.close(); + + return result; + } + + resource() : data(0), size(0) { + } + + ~resource() { + if(data) delete[] data; + } +}; + +} + +#endif diff --git a/nall/serial.hpp b/nall/serial.hpp new file mode 100755 index 00000000..9ac8451a --- /dev/null +++ b/nall/serial.hpp @@ -0,0 +1,85 @@ +#ifndef NALL_SERIAL_HPP +#define NALL_SERIAL_HPP + +#include +#include +#include +#include + +#include + +namespace nall { + class serial { + public: + //-1 on error, otherwise return bytes read + int read(uint8_t *data, unsigned length) { + if(port_open == false) return -1; + return ::read(port, (void*)data, length); + } + + //-1 on error, otherwise return bytes written + int write(const uint8_t *data, unsigned length) { + if(port_open == false) return -1; + return ::write(port, (void*)data, length); + } + + bool open(const char *portname, unsigned rate, bool flowcontrol) { + close(); + + port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); + if(port == -1) return false; + + if(ioctl(port, TIOCEXCL) == -1) { close(); return false; } + if(fcntl(port, F_SETFL, 0) == -1) { close(); return false; } + if(tcgetattr(port, &original_attr) == -1) { close(); return false; } + + termios attr = original_attr; + cfmakeraw(&attr); + cfsetspeed(&attr, rate); + + attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN); + attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY); + attr.c_iflag |= (IGNBRK | IGNPAR); + attr.c_oflag &=~ (OPOST); + attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL); + attr.c_cflag |= (CS8 | CREAD); + if(flowcontrol == false) { + attr.c_cflag &= ~CRTSCTS; + } else { + attr.c_cflag |= CRTSCTS; + } + attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0; + + if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; } + return port_open = true; + } + + void close() { + if(port != -1) { + tcdrain(port); + if(port_open == true) { + tcsetattr(port, TCSANOW, &original_attr); + port_open = false; + } + ::close(port); + port = -1; + } + } + + serial() { + port = -1; + port_open = false; + } + + ~serial() { + close(); + } + + private: + int port; + bool port_open; + termios original_attr; + }; +} + +#endif diff --git a/nall/serializer.hpp b/nall/serializer.hpp new file mode 100755 index 00000000..ff2337ab --- /dev/null +++ b/nall/serializer.hpp @@ -0,0 +1,146 @@ +#ifndef NALL_SERIALIZER_HPP +#define NALL_SERIALIZER_HPP + +#include +#include +#include +#include + +namespace nall { + //serializer: a class designed to save and restore the state of classes. + // + //benefits: + //- data() will be portable in size (it is not necessary to specify type sizes.) + //- data() will be portable in endianness (always stored internally as little-endian.) + //- one serialize function can both save and restore class states. + // + //caveats: + //- only plain-old-data can be stored. complex classes must provide serialize(serializer&); + //- floating-point usage is not portable across platforms + + class serializer { + public: + enum mode_t { Load, Save, Size }; + + mode_t mode() const { + return imode; + } + + const uint8_t* data() const { + return idata; + } + + unsigned size() const { + return isize; + } + + unsigned capacity() const { + return icapacity; + } + + template void floatingpoint(T &value) { + enum { size = sizeof(T) }; + //this is rather dangerous, and not cross-platform safe; + //but there is no standardized way to export FP-values + uint8_t *p = (uint8_t*)&value; + if(imode == Save) { + for(unsigned n = 0; n < size; n++) idata[isize++] = p[n]; + } else if(imode == Load) { + for(unsigned n = 0; n < size; n++) p[n] = idata[isize++]; + } else { + isize += size; + } + } + + template void integer(T &value) { + enum { size = std::is_same::value ? 1 : sizeof(T) }; + if(imode == Save) { + for(unsigned n = 0; n < size; n++) idata[isize++] = value >> (n << 3); + } else if(imode == Load) { + value = 0; + for(unsigned n = 0; n < size; n++) value |= idata[isize++] << (n << 3); + } else if(imode == Size) { + isize += size; + } + } + + template void array(T &array) { + enum { size = sizeof(T) / sizeof(typename std::remove_extent::type) }; + for(unsigned n = 0; n < size; n++) integer(array[n]); + } + + template void array(T array, unsigned size) { + for(unsigned n = 0; n < size; n++) integer(array[n]); + } + + //copy + serializer& operator=(const serializer &s) { + if(idata) delete[] idata; + + imode = s.imode; + idata = new uint8_t[s.icapacity]; + isize = s.isize; + icapacity = s.icapacity; + + memcpy(idata, s.idata, s.icapacity); + return *this; + } + + serializer(const serializer &s) : idata(0) { + operator=(s); + } + + //move + serializer& operator=(serializer &&s) { + if(idata) delete[] idata; + + imode = s.imode; + idata = s.idata; + isize = s.isize; + icapacity = s.icapacity; + + s.idata = 0; + return *this; + } + + serializer(serializer &&s) { + operator=(std::move(s)); + } + + //construction + serializer() { + imode = Size; + idata = 0; + isize = 0; + icapacity = 0; + } + + serializer(unsigned capacity) { + imode = Save; + idata = new uint8_t[capacity](); + isize = 0; + icapacity = capacity; + } + + serializer(const uint8_t *data, unsigned capacity) { + imode = Load; + idata = new uint8_t[capacity]; + isize = 0; + icapacity = capacity; + memcpy(idata, data, capacity); + } + + ~serializer() { + if(idata) delete[] idata; + } + + private: + mode_t imode; + uint8_t *idata; + unsigned isize; + unsigned icapacity; + }; + +}; + +#endif diff --git a/nall/sha256.hpp b/nall/sha256.hpp new file mode 100755 index 00000000..c63367a7 --- /dev/null +++ b/nall/sha256.hpp @@ -0,0 +1,145 @@ +#ifndef NALL_SHA256_HPP +#define NALL_SHA256_HPP + +//author: vladitx + +#include + +namespace nall { + #define PTR(t, a) ((t*)(a)) + + #define SWAP32(x) ((uint32_t)( \ + (((uint32_t)(x) & 0x000000ff) << 24) | \ + (((uint32_t)(x) & 0x0000ff00) << 8) | \ + (((uint32_t)(x) & 0x00ff0000) >> 8) | \ + (((uint32_t)(x) & 0xff000000) >> 24) \ + )) + + #define ST32(a, d) *PTR(uint32_t, a) = (d) + #define ST32BE(a, d) ST32(a, SWAP32(d)) + + #define LD32(a) *PTR(uint32_t, a) + #define LD32BE(a) SWAP32(LD32(a)) + + #define LSL32(x, n) ((uint32_t)(x) << (n)) + #define LSR32(x, n) ((uint32_t)(x) >> (n)) + #define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n))) + + //first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19 + static const uint32_t T_H[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, + }; + + //first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311 + static const uint32_t T_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + }; + + struct sha256_ctx { + uint8_t in[64]; + unsigned inlen; + + uint32_t w[64]; + uint32_t h[8]; + uint64_t len; + }; + + inline void sha256_init(sha256_ctx *p) { + memset(p, 0, sizeof(sha256_ctx)); + memcpy(p->h, T_H, sizeof(T_H)); + } + + static void sha256_block(sha256_ctx *p) { + unsigned i; + uint32_t s0, s1; + uint32_t a, b, c, d, e, f, g, h; + uint32_t t1, t2, maj, ch; + + for(i = 0; i < 16; i++) p->w[i] = LD32BE(p->in + i * 4); + + for(i = 16; i < 64; i++) { + s0 = ROR32(p->w[i - 15], 7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15], 3); + s1 = ROR32(p->w[i - 2], 17) ^ ROR32(p->w[i - 2], 19) ^ LSR32(p->w[i - 2], 10); + p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1; + } + + a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3]; + e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7]; + + for(i = 0; i < 64; i++) { + s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22); + maj = (a & b) ^ (a & c) ^ (b & c); + t2 = s0 + maj; + s1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25); + ch = (e & f) ^ (~e & g); + t1 = h + s1 + ch + T_K[i] + p->w[i]; + + h = g; g = f; f = e; e = d + t1; + d = c; c = b; b = a; a = t1 + t2; + } + + p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d; + p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h; + + //next block + p->inlen = 0; + } + + inline void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) { + unsigned l; + p->len += len; + + while(len) { + l = 64 - p->inlen; + l = (len < l) ? len : l; + + memcpy(p->in + p->inlen, s, l); + s += l; + p->inlen += l; + len -= l; + + if(p->inlen == 64) sha256_block(p); + } + } + + inline void sha256_final(sha256_ctx *p) { + uint64_t len; + p->in[p->inlen++] = 0x80; + + if(p->inlen > 56) { + memset(p->in + p->inlen, 0, 64 - p->inlen); + sha256_block(p); + } + + memset(p->in + p->inlen, 0, 56 - p->inlen); + + len = p->len << 3; + ST32BE(p->in + 56, len >> 32); + ST32BE(p->in + 60, len); + sha256_block(p); + } + + inline void sha256_hash(sha256_ctx *p, uint8_t *s) { + uint32_t *t = (uint32_t*)s; + for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]); + } + + #undef PTR + #undef SWAP32 + #undef ST32 + #undef ST32BE + #undef LD32 + #undef LD32BE + #undef LSL32 + #undef LSR32 + #undef ROR32 +} + +#endif diff --git a/nall/snes/cartridge.hpp b/nall/snes/cartridge.hpp new file mode 100755 index 00000000..cac3fb1a --- /dev/null +++ b/nall/snes/cartridge.hpp @@ -0,0 +1,792 @@ +#ifndef NALL_SNES_CARTRIDGE_HPP +#define NALL_SNES_CARTRIDGE_HPP + +namespace nall { + +class SnesCartridge { +public: + string markup; + inline SnesCartridge(const uint8_t *data, unsigned size); + +//private: + inline void read_header(const uint8_t *data, unsigned size); + inline unsigned find_header(const uint8_t *data, unsigned size); + inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr); + inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size); + inline bool gameboy_has_rtc(const uint8_t *data, unsigned size); + + enum HeaderField { + CartName = 0x00, + Mapper = 0x15, + RomType = 0x16, + RomSize = 0x17, + RamSize = 0x18, + CartRegion = 0x19, + Company = 0x1a, + Version = 0x1b, + Complement = 0x1c, //inverse checksum + Checksum = 0x1e, + ResetVector = 0x3c, + }; + + enum Mode { + ModeNormal, + ModeBsxSlotted, + ModeBsx, + ModeSufamiTurbo, + ModeSuperGameBoy, + }; + + enum Type { + TypeNormal, + TypeBsxSlotted, + TypeBsxBios, + TypeBsx, + TypeSufamiTurboBios, + TypeSufamiTurbo, + TypeSuperGameBoy1Bios, + TypeSuperGameBoy2Bios, + TypeGameBoy, + TypeUnknown, + }; + + enum Region { + NTSC, + PAL, + }; + + enum MemoryMapper { + LoROM, + HiROM, + ExLoROM, + ExHiROM, + SuperFXROM, + SA1ROM, + SPC7110ROM, + BSCLoROM, + BSCHiROM, + BSXROM, + STROM, + }; + + enum DSP1MemoryMapper { + DSP1Unmapped, + DSP1LoROM1MB, + DSP1LoROM2MB, + DSP1HiROM, + }; + + bool loaded; //is a base cartridge inserted? + unsigned crc32; //crc32 of all cartridges (base+slot(s)) + unsigned rom_size; + unsigned ram_size; + + Mode mode; + Type type; + Region region; + MemoryMapper mapper; + DSP1MemoryMapper dsp1_mapper; + + bool has_bsx_slot; + bool has_superfx; + bool has_sa1; + bool has_srtc; + bool has_sdd1; + bool has_spc7110; + bool has_spc7110rtc; + bool has_cx4; + bool has_dsp1; + bool has_dsp2; + bool has_dsp3; + bool has_dsp4; + bool has_obc1; + bool has_st010; + bool has_st011; + bool has_st018; +}; + +#define T "\t" + +SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) { + read_header(data, size); + + string xml; + markup = ""; + + if(type == TypeBsx) { + markup.append("cartridge"); + return; + } + + if(type == TypeSufamiTurbo) { + markup.append("cartridge"); + return; + } + + if(type == TypeGameBoy) { + markup.append("cartridge rtc=", gameboy_has_rtc(data, size), "\n"); + if(gameboy_ram_size(data, size) > 0) { + markup.append(T "ram size=0x", hex(gameboy_ram_size(data, size)), "\n"); + } + return; + } + + markup.append("cartridge region=", region == NTSC ? "NTSC\n" : "PAL\n"); + + if(type == TypeSuperGameBoy1Bios) { + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); + markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); + markup.append(T "icd2 revision=1\n"); + markup.append(T T "map address=00-3f:6000-7fff\n"); + markup.append(T T "map address=80-bf:6000-7fff\n"); + } else if(type == TypeSuperGameBoy2Bios) { + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); + markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); + markup.append(T "icd2 revision=1\n"); + markup.append(T T "map address=00-3f:6000-7fff\n"); + markup.append(T T "map address=80-bf:6000-7fff\n"); + } else if(has_cx4) { + markup.append(T "hitachidsp model=HG51B169 frequency=20000000 firmware=cx4.bin sha256=ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18\n"); + markup.append(T T "rom\n"); + markup.append(T T T "map mode=linear address=00-7f:8000-ffff\n"); + markup.append(T T T "map mode=linear address=80-ff:8000-ffff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:6000-7fff\n"); + markup.append(T T T "map address=80-bf:6000-7fff\n"); + } else if(has_spc7110) { + markup.append(T "rom\n"); + markup.append(T T "map mode=shadow address=00-0f:8000-ffff\n"); + markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n"); + markup.append(T T "map mode=linear address=c0-cf:0000-ffff\n"); + + markup.append(T "spc7110\n"); + markup.append(T T "mcu\n"); + markup.append(T T T "map address=d0-ff:0000-ffff offset=0x100000 size=0x", hex(size - 0x100000), "\n"); + markup.append(T T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T T "map mode=linear address=00:6000-7fff\n"); + markup.append(T T T "map mode=linear address=30:6000-7fff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:4800-483f\n"); + markup.append(T T T "map address=80-bf:4800-483f\n"); + if(has_spc7110rtc) { + markup.append(T T "rtc\n"); + markup.append(T T T "map address=00-3f:4840-4842\n"); + markup.append(T T T "map address=80-bf:4840-4842\n"); + } + markup.append(T T "dcu\n"); + markup.append(T T T "map address=50:0000-ffff\n"); + } else if(mapper == LoROM) { + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); + markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); + + if(ram_size > 0) { + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); + if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); + markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n"); + } else { + markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); + markup.append(T T "map mode=linear address=f0-ff:0000-ffff\n"); + } + } + } else if(mapper == HiROM) { + markup.append(T "rom\n"); + markup.append(T T "map mode=shadow address=00-3f:8000-ffff\n"); + markup.append(T T "map mode=linear address=40-7f:0000-ffff\n"); + markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n"); + markup.append(T T "map mode=linear address=c0-ff:0000-ffff\n"); + + if(ram_size > 0) { + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); + if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); + } else { + markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); + } + } + } else if(mapper == ExLoROM) { + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-3f:8000-ffff\n"); + markup.append(T T "map mode=linear address=40-7f:0000-ffff\n"); + markup.append(T T "map mode=linear address=80-bf:8000-ffff\n"); + + if(ram_size > 0) { + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); + } + } else if(mapper == ExHiROM) { + markup.append(T "rom\n"); + markup.append(T T "map mode=shadow address=00-3f:8000-ffff offset=0x400000\n"); + markup.append(T T "map mode=linear address=40-7f:0000-ffff offset=0x400000\n"); + markup.append(T T "map mode=shadow address=80-bf:8000-ffff offset=0x000000\n"); + markup.append(T T "map mode=linear address=c0-ff:0000-ffff offset=0x000000\n"); + + if(ram_size > 0) { + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); + if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); + } else { + markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); + } + } + } else if(mapper == SuperFXROM) { + markup.append(T "superfx revision=2\n"); + markup.append(T T "rom\n"); + markup.append(T T T "map mode=linear address=00-3f:8000-ffff\n"); + markup.append(T T T "map mode=linear address=40-5f:0000-ffff\n"); + markup.append(T T T "map mode=linear address=80-bf:8000-ffff\n"); + markup.append(T T T "map mode=linear address=c0-df:0000-ffff\n"); + markup.append(T T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T T "map mode=linear address=00-3f:6000-7fff size=0x2000\n"); + markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n"); + markup.append(T T T "map mode=linear address=80-bf:6000-7fff size=0x2000\n"); + markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:3000-32ff\n"); + markup.append(T T T "map address=80-bf:3000-32ff\n"); + } else if(mapper == SA1ROM) { + markup.append(T "sa1\n"); + markup.append(T T "mcu\n"); + markup.append(T T T "rom\n"); + markup.append(T T T T "map mode=direct address=00-3f:8000-ffff\n"); + markup.append(T T T T "map mode=direct address=80-bf:8000-ffff\n"); + markup.append(T T T T "map mode=direct address=c0-ff:0000-ffff\n"); + markup.append(T T T "ram\n"); + markup.append(T T T T "map mode=direct address=00-3f:6000-7fff\n"); + markup.append(T T T T "map mode=direct address=80-bf:6000-7fff\n"); + markup.append(T T "iram size=0x800\n"); + markup.append(T T T "map mode=linear address=00-3f:3000-37ff\n"); + markup.append(T T T "map mode=linear address=80-bf:3000-37ff\n"); + markup.append(T T "bwram size=0x", hex(ram_size), "\n"); + markup.append(T T T "map mode=linear address=40-4f:0000-ffff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:2200-23ff\n"); + markup.append(T T T "map address=80-bf:2200-23ff\n"); + } else if(mapper == BSCLoROM) { + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-1f:8000-ffff offset=0x000000\n"); + markup.append(T T "map mode=linear address=20-3f:8000-ffff offset=0x100000\n"); + markup.append(T T "map mode=linear address=80-9f:8000-ffff offset=0x200000\n"); + markup.append(T T "map mode=linear address=a0-bf:8000-ffff offset=0x100000\n"); + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); + markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n"); + markup.append(T "bsx\n"); + markup.append(T T "slot\n"); + markup.append(T T T "map mode=linear address=c0-ef:0000-ffff\n"); + } else if(mapper == BSCHiROM) { + markup.append(T "rom\n"); + markup.append(T T "map mode=shadow address=00-1f:8000-ffff\n"); + markup.append(T T "map mode=linear address=40-5f:0000-ffff\n"); + markup.append(T T "map mode=shadow address=80-9f:8000-ffff\n"); + markup.append(T T "map mode=linear address=c0-df:0000-ffff\n"); + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); + markup.append(T "bsx\n"); + markup.append(T T "slot\n"); + markup.append(T T T "map mode=shadow address=20-3f:8000-ffff\n"); + markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n"); + markup.append(T T T "map mode=shadow address=a0-bf:8000-ffff\n"); + markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n"); + } else if(mapper == BSXROM) { + markup.append(T "bsx\n"); + markup.append(T T "mcu\n"); + markup.append(T T T "map address=00-3f:8000-ffff\n"); + markup.append(T T T "map address=80-bf:8000-ffff\n"); + markup.append(T T T "map address=40-7f:0000-ffff\n"); + markup.append(T T T "map address=c0-ff:0000-ffff\n"); + markup.append(T T T "map address=20-3f:6000-7fff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:5000-5fff\n"); + markup.append(T T T "map address=80-bf:5000-5fff\n"); + } else if(mapper == STROM) { + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-1f:8000-ffff\n"); + markup.append(T T "map mode=linear address=80-9f:8000-ffff\n"); + markup.append(T "sufamiturbo\n"); + markup.append(T T "slot id=A\n"); + markup.append(T T T "rom\n"); + markup.append(T T T T "map mode=linear address=20-3f:8000-ffff\n"); + markup.append(T T T T "map mode=linear address=a0-bf:8000-ffff\n"); + markup.append(T T T "ram size=0x20000\n"); + markup.append(T T T T "map mode=linear address=60-63:8000-ffff\n"); + markup.append(T T T T "map mode=linear address=e0-e3:8000-ffff\n"); + markup.append(T T "slot id=B\n"); + markup.append(T T T "rom\n"); + markup.append(T T T T "map mode=linear address=40-5f:8000-ffff\n"); + markup.append(T T T T "map mode=linear address=c0-df:8000-ffff\n"); + markup.append(T T T "ram size=0x20000\n"); + markup.append(T T T T "map mode=linear address=70-73:8000-ffff\n"); + markup.append(T T T T "map mode=linear address=f0-f3:8000-ffff\n"); + } + + if(has_srtc) { + markup.append(T "srtc\n"); + markup.append(T T "map address=00-3f:2800-2801\n"); + markup.append(T T "map address=80-bf:2800-2801\n"); + } + + if(has_sdd1) { + markup.append(T "sdd1\n"); + markup.append(T T "mcu\n"); + markup.append(T T T "map address=c0-ff:0000-ffff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:4800-4807\n"); + markup.append(T T T "map address=80-bf:4800-4807\n"); + } + + if(has_dsp1) { + markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp1b.bin sha256=4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c\n"); + if(dsp1_mapper == DSP1LoROM1MB) { + markup.append(T T "dr\n"); + markup.append(T T T "map address=20-3f:8000-bfff\n"); + markup.append(T T T "map address=a0-bf:8000-bfff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=20-3f:c000-ffff\n"); + markup.append(T T T "map address=a0-bf:c000-ffff\n"); + } else if(dsp1_mapper == DSP1LoROM2MB) { + markup.append(T T "dr\n"); + markup.append(T T T "map address=60-6f:0000-3fff\n"); + markup.append(T T T "map address=e0-ef:0000-3fff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=60-6f:4000-7fff\n"); + markup.append(T T T "map address=e0-ef:4000-7fff\n"); + } else if(dsp1_mapper == DSP1HiROM) { + markup.append(T T "dr\n"); + markup.append(T T T "map address=00-1f:6000-6fff\n"); + markup.append(T T T "map address=80-9f:6000-6fff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=00-1f:7000-7fff\n"); + markup.append(T T T "map address=80-9f:7000-7fff\n"); + } + } + + if(has_dsp2) { + markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp2.bin sha256=5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=20-3f:8000-bfff\n"); + markup.append(T T T "map address=a0-bf:8000-bfff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=20-3f:c000-ffff\n"); + markup.append(T T T "map address=a0-bf:c000-ffff\n"); + } + + if(has_dsp3) { + markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp3.bin sha256=2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=20-3f:8000-bfff\n"); + markup.append(T T T "map address=a0-bf:8000-bfff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=20-3f:c000-ffff\n"); + markup.append(T T T "map address=a0-bf:c000-ffff\n"); + } + + if(has_dsp4) { + markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp4.bin sha256=63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=30-3f:8000-bfff\n"); + markup.append(T T T "map address=b0-bf:8000-bfff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=30-3f:c000-ffff\n"); + markup.append(T T T "map address=b0-bf:c000-ffff\n"); + } + + if(has_obc1) { + markup.append(T "obc1\n"); + markup.append(T T "map address=00-3f:6000-7fff\n"); + markup.append(T T "map address=80-bf:6000-7fff\n"); + } + + if(has_st010) { + markup.append(T "necdsp model=uPD96050 frequency=10000000 firmware=st0010.bin sha256=55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=60:0000\n"); + markup.append(T T T "map address=e0:0000\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=60:0001\n"); + markup.append(T T T "map address=e0:0001\n"); + markup.append(T T "dp\n"); + markup.append(T T T "map address=68-6f:0000-0fff\n"); + markup.append(T T T "map address=e8-ef:0000-0fff\n"); + } + + if(has_st011) { + markup.append(T "necdsp model=uPD96050 frequency=15000000 firmware=st0011.bin sha256=651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=60:0000\n"); + markup.append(T T T "map address=e0:0000\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=60:0001\n"); + markup.append(T T T "map address=e0:0001\n"); + markup.append(T T "dp\n"); + markup.append(T T T "map address=68-6f:0000-0fff\n"); + markup.append(T T T "map address=e8-ef:0000-0fff\n"); + } + + if(has_st018) { + markup.append(T "setarisc firmware=ST-0018\n"); + markup.append(T T "map address=00-3f:3800-38ff\n"); + markup.append(T T "map address=80-bf:3800-38ff\n"); + } +} + +#undef T + +void SnesCartridge::read_header(const uint8_t *data, unsigned size) { + type = TypeUnknown; + mapper = LoROM; + dsp1_mapper = DSP1Unmapped; + region = NTSC; + rom_size = size; + ram_size = 0; + + has_bsx_slot = false; + has_superfx = false; + has_sa1 = false; + has_srtc = false; + has_sdd1 = false; + has_spc7110 = false; + has_spc7110rtc = false; + has_cx4 = false; + has_dsp1 = false; + has_dsp2 = false; + has_dsp3 = false; + has_dsp4 = false; + has_obc1 = false; + has_st010 = false; + has_st011 = false; + has_st018 = false; + + //===================== + //detect Game Boy carts + //===================== + + if(size >= 0x0140) { + if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66 + && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) { + type = TypeGameBoy; + return; + } + } + + if(size < 32768) { + type = TypeUnknown; + return; + } + + const unsigned index = find_header(data, size); + const uint8_t mapperid = data[index + Mapper]; + const uint8_t rom_type = data[index + RomType]; + const uint8_t rom_size = data[index + RomSize]; + const uint8_t company = data[index + Company]; + const uint8_t regionid = data[index + CartRegion] & 0x7f; + + ram_size = 1024 << (data[index + RamSize] & 7); + if(ram_size == 1024) ram_size = 0; //no RAM present + + //0, 1, 13 = NTSC; 2 - 12 = PAL + region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL; + + //======================= + //detect BS-X flash carts + //======================= + + if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) { + if(data[index + 0x14] == 0x00) { + const uint8_t n15 = data[index + 0x15]; + if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) { + if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) { + type = TypeBsx; + mapper = BSXROM; + region = NTSC; //BS-X only released in Japan + return; + } + } + } + } + + //========================= + //detect Sufami Turbo carts + //========================= + + if(!memcmp(data, "BANDAI SFC-ADX", 14)) { + if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) { + type = TypeSufamiTurboBios; + } else { + type = TypeSufamiTurbo; + } + mapper = STROM; + region = NTSC; //Sufami Turbo only released in Japan + return; //RAM size handled outside this routine + } + + //========================== + //detect Super Game Boy BIOS + //========================== + + if(!memcmp(data + index, "Super GAMEBOY2", 14)) { + type = TypeSuperGameBoy2Bios; + return; + } + + if(!memcmp(data + index, "Super GAMEBOY", 13)) { + type = TypeSuperGameBoy1Bios; + return; + } + + //===================== + //detect standard carts + //===================== + + //detect presence of BS-X flash cartridge connector (reads extended header information) + if(data[index - 14] == 'Z') { + if(data[index - 11] == 'J') { + uint8_t n13 = data[index - 13]; + if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) { + if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) { + has_bsx_slot = true; + } + } + } + } + + if(has_bsx_slot) { + if(!memcmp(data + index, "Satellaview BS-X ", 21)) { + //BS-X base cart + type = TypeBsxBios; + mapper = BSXROM; + region = NTSC; //BS-X only released in Japan + return; //RAM size handled internally by load_cart_bsx() -> BSXCart class + } else { + type = TypeBsxSlotted; + mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM); + region = NTSC; //BS-X slotted cartridges only released in Japan + } + } else { + //standard cart + type = TypeNormal; + + if(index == 0x7fc0 && size >= 0x401000) { + mapper = ExLoROM; + } else if(index == 0x7fc0 && mapperid == 0x32) { + mapper = ExLoROM; + } else if(index == 0x7fc0) { + mapper = LoROM; + } else if(index == 0xffc0) { + mapper = HiROM; + } else { //index == 0x40ffc0 + mapper = ExHiROM; + } + } + + if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { + has_superfx = true; + mapper = SuperFXROM; + ram_size = 1024 << (data[index - 3] & 7); + if(ram_size == 1024) ram_size = 0; + } + + if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) { + has_sa1 = true; + mapper = SA1ROM; + } + + if(mapperid == 0x35 && rom_type == 0x55) { + has_srtc = true; + } + + if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) { + has_sdd1 = true; + } + + if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) { + has_spc7110 = true; + has_spc7110rtc = (rom_type == 0xf9); + mapper = SPC7110ROM; + } + + if(mapperid == 0x20 && rom_type == 0xf3) { + has_cx4 = true; + } + + if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) { + has_dsp1 = true; + } + + if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) { + has_dsp1 = true; + } + + if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) { + has_dsp1 = true; + } + + if(has_dsp1 == true) { + if((mapperid & 0x2f) == 0x20 && size <= 0x100000) { + dsp1_mapper = DSP1LoROM1MB; + } else if((mapperid & 0x2f) == 0x20) { + dsp1_mapper = DSP1LoROM2MB; + } else if((mapperid & 0x2f) == 0x21) { + dsp1_mapper = DSP1HiROM; + } + } + + if(mapperid == 0x20 && rom_type == 0x05) { + has_dsp2 = true; + } + + if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) { + has_dsp3 = true; + } + + if(mapperid == 0x30 && rom_type == 0x03) { + has_dsp4 = true; + } + + if(mapperid == 0x30 && rom_type == 0x25) { + has_obc1 = true; + } + + if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) { + has_st010 = true; + } + + if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) { + has_st011 = true; + } + + if(mapperid == 0x30 && rom_type == 0xf5) { + has_st018 = true; + } +} + +unsigned SnesCartridge::find_header(const uint8_t *data, unsigned size) { + unsigned score_lo = score_header(data, size, 0x007fc0); + unsigned score_hi = score_header(data, size, 0x00ffc0); + unsigned score_ex = score_header(data, size, 0x40ffc0); + if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits + + if(score_lo >= score_hi && score_lo >= score_ex) { + return 0x007fc0; + } else if(score_hi >= score_ex) { + return 0x00ffc0; + } else { + return 0x40ffc0; + } +} + +unsigned SnesCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) { + if(size < addr + 64) return 0; //image too small to contain header at this location? + int score = 0; + + uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8); + uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8); + uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8); + + uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset + uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit + + //$00:[000-7fff] contains uninitialized RAM and MMIO. + //reset vector must point to ROM at $00:[8000-ffff] to be considered valid. + if(resetvector < 0x8000) return 0; + + //some images duplicate the header in multiple locations, and others have completely + //invalid header information that cannot be relied upon. + //below code will analyze the first opcode executed at the specified reset vector to + //determine the probability that this is the correct header. + + //most likely opcodes + if(resetop == 0x78 //sei + || resetop == 0x18 //clc (clc; xce) + || resetop == 0x38 //sec (sec; xce) + || resetop == 0x9c //stz $nnnn (stz $4200) + || resetop == 0x4c //jmp $nnnn + || resetop == 0x5c //jml $nnnnnn + ) score += 8; + + //plausible opcodes + if(resetop == 0xc2 //rep #$nn + || resetop == 0xe2 //sep #$nn + || resetop == 0xad //lda $nnnn + || resetop == 0xae //ldx $nnnn + || resetop == 0xac //ldy $nnnn + || resetop == 0xaf //lda $nnnnnn + || resetop == 0xa9 //lda #$nn + || resetop == 0xa2 //ldx #$nn + || resetop == 0xa0 //ldy #$nn + || resetop == 0x20 //jsr $nnnn + || resetop == 0x22 //jsl $nnnnnn + ) score += 4; + + //implausible opcodes + if(resetop == 0x40 //rti + || resetop == 0x60 //rts + || resetop == 0x6b //rtl + || resetop == 0xcd //cmp $nnnn + || resetop == 0xec //cpx $nnnn + || resetop == 0xcc //cpy $nnnn + ) score -= 4; + + //least likely opcodes + if(resetop == 0x00 //brk #$nn + || resetop == 0x02 //cop #$nn + || resetop == 0xdb //stp + || resetop == 0x42 //wdm + || resetop == 0xff //sbc $nnnnnn,x + ) score -= 8; + + //at times, both the header and reset vector's first opcode will match ... + //fallback and rely on info validity in these cases to determine more likely header. + + //a valid checksum is the biggest indicator of a valid header. + if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4; + + if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM + if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM + if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM + if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM + + if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header + if(data[addr + RomType] < 0x08) score++; + if(data[addr + RomSize] < 0x10) score++; + if(data[addr + RamSize] < 0x08) score++; + if(data[addr + CartRegion] < 14) score++; + + if(score < 0) score = 0; + return score; +} + +unsigned SnesCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) { + if(size < 512) return 0; + switch(data[0x0149]) { + case 0x00: return 0 * 1024; + case 0x01: return 8 * 1024; + case 0x02: return 8 * 1024; + case 0x03: return 32 * 1024; + case 0x04: return 128 * 1024; + case 0x05: return 128 * 1024; + default: return 128 * 1024; + } +} + +bool SnesCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) { + if(size < 512) return false; + if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true; + return false; +} + +} + +#endif diff --git a/nall/snes/cpu.hpp b/nall/snes/cpu.hpp new file mode 100755 index 00000000..28f5ddb5 --- /dev/null +++ b/nall/snes/cpu.hpp @@ -0,0 +1,458 @@ +#ifndef NALL_SNES_CPU_HPP +#define NALL_SNES_CPU_HPP + +namespace nall { + +struct SNESCPU { + enum : unsigned { + Implied, // + Constant, //#$00 + AccumConstant, //#$00 + IndexConstant, //#$00 + Direct, //$00 + DirectX, //$00,x + DirectY, //$00,y + IDirect, //($00) + IDirectX, //($00,x) + IDirectY, //($00),y + ILDirect, //[$00] + ILDirectY, //[$00],y + Address, //$0000 + AddressX, //$0000,x + AddressY, //$0000,y + IAddressX, //($0000,x) + ILAddress, //[$0000] + PAddress, //PBR:$0000 + PIAddress, //PBR:($0000) + Long, //$000000 + LongX, //$000000,x + Stack, //$00,s + IStackY, //($00,s),y + BlockMove, //$00,$00 + RelativeShort, //+/- $00 + RelativeLong, //+/- $0000 + }; + + struct OpcodeInfo { + char name[4]; + unsigned mode; + }; + + static const OpcodeInfo opcodeInfo[256]; + + static unsigned getOpcodeLength(bool accum, bool index, uint8_t opcode); + static string disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb); +}; + +const SNESCPU::OpcodeInfo SNESCPU::opcodeInfo[256] = { + //0x00 - 0x0f + { "brk", Constant }, + { "ora", IDirectX }, + { "cop", Constant }, + { "ora", Stack }, + + { "tsb", Direct }, + { "ora", Direct }, + { "asl", Direct }, + { "ora", ILDirect }, + + { "php", Implied }, + { "ora", AccumConstant }, + { "asl", Implied }, + { "phd", Implied }, + + { "tsb", Address }, + { "ora", Address }, + { "asl", Address }, + { "ora", Long }, + + //0x10 - 0x1f + { "bpl", RelativeShort }, + { "ora", IDirectY }, + { "ora", IDirect }, + { "ora", IStackY }, + + { "trb", Direct }, + { "ora", DirectX }, + { "asl", DirectX }, + { "ora", ILDirectY }, + + { "clc", Implied }, + { "ora", AddressY }, + { "inc", Implied }, + { "tcs", Implied }, + + { "trb", Address }, + { "ora", AddressX }, + { "asl", AddressX }, + { "ora", LongX }, + + //0x20 - 0x2f + { "jsr", Address }, + { "and", IDirectX }, + { "jsl", Long }, + { "and", Stack }, + + { "bit", Direct }, + { "and", Direct }, + { "rol", Direct }, + { "and", ILDirect }, + + { "plp", Implied }, + { "and", AccumConstant }, + { "rol", Implied }, + { "pld", Implied }, + + { "bit", Address }, + { "and", Address }, + { "rol", Address }, + { "and", Long }, + + //0x30 - 0x3f + { "bmi", RelativeShort }, + { "and", IDirectY }, + { "and", IDirect }, + { "and", IStackY }, + + { "bit", DirectX }, + { "and", DirectX }, + { "rol", DirectX }, + { "and", ILDirectY }, + + { "sec", Implied }, + { "and", AddressY }, + { "dec", Implied }, + { "tsc", Implied }, + + { "bit", AddressX }, + { "and", AddressX }, + { "rol", AddressX }, + { "and", LongX }, + + //0x40 - 0x4f + { "rti", Implied }, + { "eor", IDirectX }, + { "wdm", Constant }, + { "eor", Stack }, + + { "mvp", BlockMove }, + { "eor", Direct }, + { "lsr", Direct }, + { "eor", ILDirect }, + + { "pha", Implied }, + { "eor", AccumConstant }, + { "lsr", Implied }, + { "phk", Implied }, + + { "jmp", PAddress }, + { "eor", Address }, + { "lsr", Address }, + { "eor", Long }, + + //0x50 - 0x5f + { "bvc", RelativeShort }, + { "eor", IDirectY }, + { "eor", IDirect }, + { "eor", IStackY }, + + { "mvn", BlockMove }, + { "eor", DirectX }, + { "lsr", DirectX }, + { "eor", ILDirectY }, + + { "cli", Implied }, + { "eor", AddressY }, + { "phy", Implied }, + { "tcd", Implied }, + + { "jml", Long }, + { "eor", AddressX }, + { "lsr", AddressX }, + { "eor", LongX }, + + //0x60 - 0x6f + { "rts", Implied }, + { "adc", IDirectX }, + { "per", Address }, + { "adc", Stack }, + + { "stz", Direct }, + { "adc", Direct }, + { "ror", Direct }, + { "adc", ILDirect }, + + { "pla", Implied }, + { "adc", AccumConstant }, + { "ror", Implied }, + { "rtl", Implied }, + + { "jmp", PIAddress }, + { "adc", Address }, + { "ror", Address }, + { "adc", Long }, + + //0x70 - 0x7f + { "bvs", RelativeShort }, + { "adc", IDirectY }, + { "adc", IDirect }, + { "adc", IStackY }, + + { "stz", DirectX }, + { "adc", DirectX }, + { "ror", DirectX }, + { "adc", ILDirectY }, + + { "sei", Implied }, + { "adc", AddressY }, + { "ply", Implied }, + { "tdc", Implied }, + + { "jmp", IAddressX }, + { "adc", AddressX }, + { "ror", AddressX }, + { "adc", LongX }, + + //0x80 - 0x8f + { "bra", RelativeShort }, + { "sta", IDirectX }, + { "brl", RelativeLong }, + { "sta", Stack }, + + { "sty", Direct }, + { "sta", Direct }, + { "stx", Direct }, + { "sta", ILDirect }, + + { "dey", Implied }, + { "bit", AccumConstant }, + { "txa", Implied }, + { "phb", Implied }, + + { "sty", Address }, + { "sta", Address }, + { "stx", Address }, + { "sta", Long }, + + //0x90 - 0x9f + { "bcc", RelativeShort }, + { "sta", IDirectY }, + { "sta", IDirect }, + { "sta", IStackY }, + + { "sty", DirectX }, + { "sta", DirectX }, + { "stx", DirectY }, + { "sta", ILDirectY }, + + { "tya", Implied }, + { "sta", AddressY }, + { "txs", Implied }, + { "txy", Implied }, + + { "stz", Address }, + { "sta", AddressX }, + { "stz", AddressX }, + { "sta", LongX }, + + //0xa0 - 0xaf + { "ldy", IndexConstant }, + { "lda", IDirectX }, + { "ldx", IndexConstant }, + { "lda", Stack }, + + { "ldy", Direct }, + { "lda", Direct }, + { "ldx", Direct }, + { "lda", ILDirect }, + + { "tay", Implied }, + { "lda", AccumConstant }, + { "tax", Implied }, + { "plb", Implied }, + + { "ldy", Address }, + { "lda", Address }, + { "ldx", Address }, + { "lda", Long }, + + //0xb0 - 0xbf + { "bcs", RelativeShort }, + { "lda", IDirectY }, + { "lda", IDirect }, + { "lda", IStackY }, + + { "ldy", DirectX }, + { "lda", DirectX }, + { "ldx", DirectY }, + { "lda", ILDirectY }, + + { "clv", Implied }, + { "lda", AddressY }, + { "tsx", Implied }, + { "tyx", Implied }, + + { "ldy", AddressX }, + { "lda", AddressX }, + { "ldx", AddressY }, + { "lda", LongX }, + + //0xc0 - 0xcf + { "cpy", IndexConstant }, + { "cmp", IDirectX }, + { "rep", Constant }, + { "cmp", Stack }, + + { "cpy", Direct }, + { "cmp", Direct }, + { "dec", Direct }, + { "cmp", ILDirect }, + + { "iny", Implied }, + { "cmp", AccumConstant }, + { "dex", Implied }, + { "wai", Implied }, + + { "cpy", Address }, + { "cmp", Address }, + { "dec", Address }, + { "cmp", Long }, + + //0xd0 - 0xdf + { "bne", RelativeShort }, + { "cmp", IDirectY }, + { "cmp", IDirect }, + { "cmp", IStackY }, + + { "pei", IDirect }, + { "cmp", DirectX }, + { "dec", DirectX }, + { "cmp", ILDirectY }, + + { "cld", Implied }, + { "cmp", AddressY }, + { "phx", Implied }, + { "stp", Implied }, + + { "jmp", ILAddress }, + { "cmp", AddressX }, + { "dec", AddressX }, + { "cmp", LongX }, + + //0xe0 - 0xef + { "cpx", IndexConstant }, + { "sbc", IDirectX }, + { "sep", Constant }, + { "sbc", Stack }, + + { "cpx", Direct }, + { "sbc", Direct }, + { "inc", Direct }, + { "sbc", ILDirect }, + + { "inx", Implied }, + { "sbc", AccumConstant }, + { "nop", Implied }, + { "xba", Implied }, + + { "cpx", Address }, + { "sbc", Address }, + { "inc", Address }, + { "sbc", Long }, + + //0xf0 - 0xff + { "beq", RelativeShort }, + { "sbc", IDirectY }, + { "sbc", IDirect }, + { "sbc", IStackY }, + + { "pea", Address }, + { "sbc", DirectX }, + { "inc", DirectX }, + { "sbc", ILDirectY }, + + { "sed", Implied }, + { "sbc", AddressY }, + { "plx", Implied }, + { "xce", Implied }, + + { "jsr", IAddressX }, + { "sbc", AddressX }, + { "inc", AddressX }, + { "sbc", LongX }, +}; + +inline unsigned SNESCPU::getOpcodeLength(bool accum, bool index, uint8_t opcode) { + switch(opcodeInfo[opcode].mode) { default: + case Implied: return 1; + case Constant: return 2; + case AccumConstant: return 3 - accum; + case IndexConstant: return 3 - index; + case Direct: return 2; + case DirectX: return 2; + case DirectY: return 2; + case IDirect: return 2; + case IDirectX: return 2; + case IDirectY: return 2; + case ILDirect: return 2; + case ILDirectY: return 2; + case Address: return 3; + case AddressX: return 3; + case AddressY: return 3; + case IAddressX: return 3; + case ILAddress: return 3; + case PAddress: return 3; + case PIAddress: return 3; + case Long: return 4; + case LongX: return 4; + case Stack: return 2; + case IStackY: return 2; + case BlockMove: return 3; + case RelativeShort: return 2; + case RelativeLong: return 3; + } +} + +inline string SNESCPU::disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb) { + string name = opcodeInfo[opcode].name; + unsigned mode = opcodeInfo[opcode].mode; + + if(mode == Implied) return name; + if(mode == Constant) return { name, " #$", hex<2>(pl) }; + if(mode == AccumConstant) return { name, " #$", accum ? "" : hex<2>(ph), hex<2>(pl) }; + if(mode == IndexConstant) return { name, " #$", index ? "" : hex<2>(ph), hex<2>(pl) }; + if(mode == Direct) return { name, " $", hex<2>(pl) }; + if(mode == DirectX) return { name, " $", hex<2>(pl), ",x" }; + if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" }; + if(mode == IDirect) return { name, " ($", hex<2>(pl), ")" }; + if(mode == IDirectX) return { name, " ($", hex<2>(pl), ",x)" }; + if(mode == IDirectY) return { name, " ($", hex<2>(pl), "),y" }; + if(mode == ILDirect) return { name, " [$", hex<2>(pl), "]" }; + if(mode == ILDirectY) return { name, " [$", hex<2>(pl), "],y" }; + if(mode == Address) return { name, " $", hex<2>(ph), hex<2>(pl) }; + if(mode == AddressX) return { name, " $", hex<2>(ph), hex<2>(pl), ",x" }; + if(mode == AddressY) return { name, " $", hex<2>(ph), hex<2>(pl), ",y" }; + if(mode == IAddressX) return { name, " ($", hex<2>(ph), hex<2>(pl), ",x)" }; + if(mode == ILAddress) return { name, " [$", hex<2>(ph), hex<2>(pl), "]" }; + if(mode == PAddress) return { name, " $", hex<2>(ph), hex<2>(pl) }; + if(mode == PIAddress) return { name, " ($", hex<2>(ph), hex<2>(pl), ")" }; + if(mode == Long) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl) }; + if(mode == LongX) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl), ",x" }; + if(mode == Stack) return { name, " $", hex<2>(pl), ",s" }; + if(mode == IStackY) return { name, " ($", hex<2>(pl), ",s),y" }; + if(mode == BlockMove) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) }; + if(mode == RelativeShort) { + unsigned addr = (pc + 2) + (int8_t)(pl << 0); + return { name, " $", hex<4>(addr) }; + } + if(mode == RelativeLong) { + unsigned addr = (pc + 3) + (int16_t)((ph << 8) + (pl << 0)); + return { name, " $", hex<4>(addr) }; + } + + return ""; +} + +} + +#endif diff --git a/nall/snes/smp.hpp b/nall/snes/smp.hpp new file mode 100755 index 00000000..7a1ac47b --- /dev/null +++ b/nall/snes/smp.hpp @@ -0,0 +1,639 @@ +#ifndef NALL_SNES_SMP_HPP +#define NALL_SNES_SMP_HPP + +namespace nall { + +struct SNESSMP { + enum : unsigned { + Implied, // + TVector, //0 + Direct, //$00 + DirectRelative, //$00,+/-$00 + ADirect, //a,$00 + AAbsolute, //a,$0000 + AIX, //a,(x) + AIDirectX, //a,($00+x) + AConstant, //a,#$00 + DirectDirect, //$00,$00 + CAbsoluteBit, //c,$0000:0 + Absolute, //$0000 + P, //p + AbsoluteA, //$0000,a + Relative, //+/-$00 + ADirectX, //a,$00+x + AAbsoluteX, //a,$0000+x + AAbsoluteY, //a,$0000+y + AIDirectY, //a,($00)+y + DirectConstant, //$00,#$00 + IXIY, //(x),(y) + DirectX, //$00+x + A, //a + X, //x + XAbsolute, //x,$0000 + IAbsoluteX, //($0000+x) + CNAbsoluteBit, //c,!$0000:0 + XDirect, //x,$00 + PVector, //$ff00 + YaDirect, //ya,$00 + XA, //x,a + YAbsolute, //y,$0000 + Y, //y + AX, //a,x + YDirect, //y,$00 + YConstant, //y,#$00 + XSp, //x,sp + YaX, //ya,x + IXPA, //(x)+,a + SpX, //sp,x + AIXP, //a,(x)+ + DirectA, //$00,a + IXA, //(x),a + IDirectXA, //($00+x),a + XConstant, //x,#$00 + AbsoluteX, //$0000,x + AbsoluteBitC, //$0000:0,c + DirectY, //$00,y + AbsoluteY, //$0000,y + Ya, //ya + DirectXA, //$00+x,a + AbsoluteXA, //$0000+x,a + AbsoluteYA, //$0000+y,a + IDirectYA, //($00)+y,a + DirectYX, //$00+y,x + DirectYa, //$00,ya + DirectXY, //$00+x,y + AY, //a,y + DirectXRelative, //$00+x,+/-$00 + XDirectY, //x,$00+y + YDirectX, //y,$00+x + YA, //y,a + YRelative, //y,+/-$00 + }; + + struct OpcodeInfo { + char name[6]; + unsigned mode; + }; + + static const OpcodeInfo opcodeInfo[256]; + + static unsigned getOpcodeLength(uint8_t opcode); + static string disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph); + static string disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph); +}; + +const SNESSMP::OpcodeInfo SNESSMP::opcodeInfo[256] = { + //0x00 - 0x0f + { "nop ", Implied }, + { "tcall", TVector }, + { "set0 ", Direct }, + { "bbs0 ", DirectRelative }, + + { "or ", ADirect }, + { "or ", AAbsolute }, + { "or ", AIX }, + { "or ", AIDirectX }, + + { "or ", AConstant }, + { "or ", DirectDirect }, + { "or1 ", CAbsoluteBit }, + { "asl ", Direct }, + + { "asl ", Absolute }, + { "push ", P }, + { "tset ", AbsoluteA }, + { "brk ", Implied }, + + //0x10 - 0x1f + { "bpl ", Relative }, + { "tcall", TVector }, + { "clr0 ", Direct }, + { "bbc0 ", DirectRelative }, + + { "or ", ADirectX }, + { "or ", AAbsoluteX }, + { "or ", AAbsoluteY }, + { "or ", AIDirectY }, + + { "or ", DirectConstant }, + { "or ", IXIY }, + { "decw ", Direct }, + { "asl ", DirectX }, + + { "asl ", A }, + { "dec ", X }, + { "cmp ", XAbsolute }, + { "jmp ", IAbsoluteX }, + + //0x20 - 0x2f + { "clrp ", Implied }, + { "tcall", TVector }, + { "set1 ", Direct }, + { "bbs1 ", DirectRelative }, + + { "and ", ADirect }, + { "and ", AAbsolute }, + { "and ", AIX }, + { "and ", AIDirectX }, + + { "and ", AConstant }, + { "and ", DirectDirect }, + { "or1 ", CNAbsoluteBit }, + { "rol ", Direct }, + + { "rol ", Absolute }, + { "push ", A }, + { "cbne ", DirectRelative }, + { "bra ", Relative }, + + //0x30 - 0x3f + { "bmi ", Relative }, + { "tcall", TVector }, + { "clr1 ", Direct }, + { "bbc1 ", DirectRelative }, + + { "and ", ADirectX }, + { "and ", AAbsoluteX }, + { "and ", AAbsoluteY }, + { "and ", AIDirectY }, + + { "and ", DirectConstant }, + { "and ", IXIY }, + { "incw ", Direct }, + { "rol ", DirectX }, + + { "rol ", A }, + { "inc ", X }, + { "cmp ", XDirect }, + { "call ", Absolute }, + + //0x40 - 0x4f + { "setp ", Implied }, + { "tcall", TVector }, + { "set2 ", Direct }, + { "bbs2 ", DirectRelative }, + + { "eor ", ADirect }, + { "eor ", AAbsolute }, + { "eor ", AIX }, + { "eor ", AIDirectX }, + + { "eor ", AConstant }, + { "eor ", DirectDirect }, + { "and1 ", CAbsoluteBit }, + { "lsr ", Direct }, + + { "lsr ", Absolute }, + { "push ", X }, + { "tclr ", AbsoluteA }, + { "pcall", PVector }, + + //0x50 - 0x5f + { "bvc ", Relative }, + { "tcall", TVector }, + { "clr2 ", Direct }, + { "bbc2 ", DirectRelative }, + + { "eor ", ADirectX }, + { "eor ", AAbsoluteX }, + { "eor ", AAbsoluteY }, + { "eor ", AIDirectY }, + + { "eor ", DirectConstant }, + { "eor ", IXIY }, + { "cmpw ", YaDirect }, + { "lsr ", DirectX }, + + { "lsr ", A }, + { "mov ", XA }, + { "cmp ", YAbsolute }, + { "jmp ", Absolute }, + + //0x60 - 0x6f + { "clrc ", Implied }, + { "tcall", TVector }, + { "set3 ", Direct }, + { "bbs3 ", DirectRelative }, + + { "cmp ", ADirect }, + { "cmp ", AAbsolute }, + { "cmp ", AIX }, + { "cmp ", AIDirectX }, + + { "cmp ", AConstant }, + { "cmp ", DirectDirect }, + { "and1 ", CNAbsoluteBit }, + { "ror ", Direct }, + + { "ror ", Absolute }, + { "push ", Y }, + { "dbnz ", DirectRelative }, + { "ret ", Implied }, + + //0x70 - 0x7f + { "bvs ", Relative }, + { "tcall", TVector }, + { "clr3 ", Direct }, + { "bbc3 ", DirectRelative }, + + { "cmp ", ADirectX }, + { "cmp ", AAbsoluteX }, + { "cmp ", AAbsoluteY }, + { "cmp ", AIDirectY }, + + { "cmp ", DirectConstant }, + { "cmp ", IXIY }, + { "addw ", YaDirect }, + { "ror ", DirectX }, + + { "ror ", A }, + { "mov ", AX }, + { "cmp ", YDirect }, + { "reti ", Implied }, + + //0x80 - 0x8f + { "setc ", Implied }, + { "tcall", TVector }, + { "set4 ", Direct }, + { "bbs4 ", DirectRelative }, + + { "adc ", ADirect }, + { "adc ", AAbsolute }, + { "adc ", AIX }, + { "adc ", AIDirectX }, + + { "adc ", AConstant }, + { "adc ", DirectDirect }, + { "eor1 ", CAbsoluteBit }, + { "dec ", Direct }, + + { "dec ", Absolute }, + { "mov ", YConstant }, + { "pop ", P }, + { "mov ", DirectConstant }, + + //0x90 - 0x9f + { "bcc ", Relative }, + { "tcall", TVector }, + { "clr4 ", Direct }, + { "bbc4 ", DirectRelative }, + + { "adc ", ADirectX }, + { "adc ", AAbsoluteX }, + { "adc ", AAbsoluteY }, + { "adc ", AIDirectY }, + + { "adc ", DirectRelative }, + { "adc ", IXIY }, + { "subw ", YaDirect }, + { "dec ", DirectX }, + + { "dec ", A }, + { "mov ", XSp }, + { "div ", YaX }, + { "xcn ", A }, + + //0xa0 - 0xaf + { "ei ", Implied }, + { "tcall", TVector }, + { "set5 ", Direct }, + { "bbs5 ", DirectRelative }, + + { "sbc ", ADirect }, + { "sbc ", AAbsolute }, + { "sbc ", AIX }, + { "sbc ", AIDirectX }, + + { "sbc ", AConstant }, + { "sbc ", DirectDirect }, + { "mov1 ", CAbsoluteBit }, + { "inc ", Direct }, + + { "inc ", Absolute }, + { "cmp ", YConstant }, + { "pop ", A }, + { "mov ", IXPA }, + + //0xb0 - 0xbf + { "bcs ", Relative }, + { "tcall", TVector }, + { "clr5 ", Direct }, + { "bbc5 ", DirectRelative }, + + { "sbc ", ADirectX }, + { "sbc ", AAbsoluteX }, + { "sbc ", AAbsoluteY }, + { "sbc ", AIDirectY }, + + { "sbc ", DirectConstant }, + { "sbc ", IXIY }, + { "movw ", YaDirect }, + { "inc ", DirectX }, + + { "inc ", A }, + { "mov ", SpX }, + { "das ", A }, + { "mov ", AIXP }, + + //0xc0 - 0xcf + { "di ", Implied }, + { "tcall", TVector }, + { "set6 ", Direct }, + { "bbs6 ", DirectRelative }, + + { "mov ", DirectA }, + { "mov ", AbsoluteA }, + { "mov ", IXA }, + { "mov ", IDirectXA }, + + { "cmp ", XConstant }, + { "mov ", AbsoluteX }, + { "mov1 ", AbsoluteBitC }, + { "mov ", DirectY }, + + { "mov ", AbsoluteY }, + { "mov ", XConstant }, + { "pop ", X }, + { "mul ", Ya }, + + //0xd0 - 0xdf + { "bne ", Relative }, + { "tcall", TVector }, + { "clr6 ", Relative }, + { "bbc6 ", DirectRelative }, + + { "mov ", DirectXA }, + { "mov ", AbsoluteXA }, + { "mov ", AbsoluteYA }, + { "mov ", IDirectYA }, + + { "mov ", DirectX }, + { "mov ", DirectYX }, + { "movw ", DirectYa }, + { "mov ", DirectXY }, + + { "dec ", Y }, + { "mov ", AY }, + { "cbne ", DirectXRelative }, + { "daa ", A }, + + //0xe0 - 0xef + { "clrv ", Implied }, + { "tcall", TVector }, + { "set7 ", Direct }, + { "bbs7 ", DirectRelative }, + + { "mov ", ADirect }, + { "mov ", AAbsolute }, + { "mov ", AIX }, + { "mov ", AIDirectX }, + + { "mov ", AConstant }, + { "mov ", XAbsolute }, + { "not1 ", CAbsoluteBit }, + { "mov ", YDirect }, + + { "mov ", YAbsolute }, + { "notc ", Implied }, + { "pop ", Y }, + { "sleep", Implied }, + + //0xf0 - 0xff + { "beq ", Relative }, + { "tcall", TVector }, + { "clr7 ", Direct }, + { "bbc7 ", DirectRelative }, + + { "mov ", ADirectX }, + { "mov ", AAbsoluteX }, + { "mov ", AAbsoluteY }, + { "mov ", AIDirectY }, + + { "mov ", XDirect }, + { "mov ", XDirectY }, + { "mov ", DirectDirect }, + { "mov ", YDirectX }, + + { "inc ", Y }, + { "mov ", YA }, + { "dbz ", YRelative }, + { "stop ", Implied }, +}; + +inline unsigned SNESSMP::getOpcodeLength(uint8_t opcode) { + switch(opcodeInfo[opcode].mode) { default: + case Implied: return 1; // + case TVector: return 1; //0 + case Direct: return 2; //$00 + case DirectRelative: return 3; //$00,+/-$00 + case ADirect: return 2; //a,$00 + case AAbsolute: return 3; //a,$0000 + case AIX: return 1; //a,(x) + case AIDirectX: return 2; //a,($00+x) + case AConstant: return 2; //a,#$00 + case DirectDirect: return 3; //$00,$00 + case CAbsoluteBit: return 3; //c,$0000:0 + case Absolute: return 3; //$0000 + case P: return 1; //p + case AbsoluteA: return 3; //$0000,a + case Relative: return 2; //+/-$00 + case ADirectX: return 2; //a,$00+x + case AAbsoluteX: return 3; //a,$0000+x + case AAbsoluteY: return 3; //a,$0000+y + case AIDirectY: return 2; //a,($00)+y + case DirectConstant: return 3; //$00,#$00 + case IXIY: return 1; //(x),(y) + case DirectX: return 2; //$00+x + case A: return 1; //a + case X: return 1; //x + case XAbsolute: return 3; //x,$0000 + case IAbsoluteX: return 3; //($0000+x) + case CNAbsoluteBit: return 3; //c,!$0000:0 + case XDirect: return 2; //x,$00 + case PVector: return 2; //$ff00 + case YaDirect: return 2; //ya,$00 + case XA: return 1; //x,a + case YAbsolute: return 3; //y,$0000 + case Y: return 1; //y + case AX: return 1; //a,x + case YDirect: return 2; //y,$00 + case YConstant: return 2; //y,#$00 + case XSp: return 1; //x,sp + case YaX: return 1; //ya,x + case IXPA: return 1; //(x)+,a + case SpX: return 1; //sp,x + case AIXP: return 1; //a,(x)+ + case DirectA: return 2; //$00,a + case IXA: return 1; //(x),a + case IDirectXA: return 2; //($00+x),a + case XConstant: return 2; //x,#$00 + case AbsoluteX: return 3; //$0000,x + case AbsoluteBitC: return 3; //$0000:0,c + case DirectY: return 2; //$00,y + case AbsoluteY: return 3; //$0000,y + case Ya: return 1; //ya + case DirectXA: return 2; //$00+x,a + case AbsoluteXA: return 3; //$0000+x,a + case AbsoluteYA: return 3; //$0000+y,a + case IDirectYA: return 2; //($00)+y,a + case DirectYX: return 2; //$00+y,x + case DirectYa: return 2; //$00,ya + case DirectXY: return 2; //$00+x,y + case AY: return 1; //a,y + case DirectXRelative: return 3; //$00+x,+/-$00 + case XDirectY: return 2; //x,$00+y + case YDirectX: return 2; //y,$00+x + case YA: return 1; //y,a + case YRelative: return 2; //y,+/-$00 + } +} + +inline string SNESSMP::disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph) { + string name = opcodeInfo[opcode].name; + unsigned mode = opcodeInfo[opcode].mode; + unsigned pa = (ph << 8) + pl; + + if(mode == Implied) return name; + if(mode == TVector) return { name, " ", opcode >> 4 }; + if(mode == Direct) return { name, " $", hex<2>(pl) }; + if(mode == DirectRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; + if(mode == ADirect) return { name, " a,$", hex<2>(pl) }; + if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) }; + if(mode == AIX) return { name, "a,(x)" }; + if(mode == AIDirectX) return { name, " a,($", hex<2>(pl), "+x)" }; + if(mode == AConstant) return { name, " a,#$", hex<2>(pl) }; + if(mode == DirectDirect) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) }; + if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; + if(mode == Absolute) return { name, " $", hex<4>(pa) }; + if(mode == P) return { name, " p" }; + if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" }; + if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) }; + if(mode == ADirectX) return { name, " a,$", hex<2>(pl), "+x" }; + if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" }; + if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" }; + if(mode == AIDirectY) return { name, " a,($", hex<2>(pl), ")+y" }; + if(mode == DirectConstant) return { name, " $", hex<2>(ph), ",#$", hex<2>(pl) }; + if(mode == IXIY) return { name, " (x),(y)" }; + if(mode == DirectX) return { name, " $", hex<2>(pl), "+x" }; + if(mode == A) return { name, " a" }; + if(mode == X) return { name, " x" }; + if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) }; + if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" }; + if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; + if(mode == XDirect) return { name, " x,$", hex<2>(pl) }; + if(mode == PVector) return { name, " $ff", hex<2>(pl) }; + if(mode == YaDirect) return { name, " ya,$", hex<2>(pl) }; + if(mode == XA) return { name, " x,a" }; + if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) }; + if(mode == Y) return { name, " y" }; + if(mode == AX) return { name, " a,x" }; + if(mode == YDirect) return { name, " y,$", hex<2>(pl) }; + if(mode == YConstant) return { name, " y,#$", hex<2>(pl) }; + if(mode == XSp) return { name, " x,sp" }; + if(mode == YaX) return { name, " ya,x" }; + if(mode == IXPA) return { name, " (x)+,a" }; + if(mode == SpX) return { name, " sp,x" }; + if(mode == AIXP) return { name, " a,(x)+" }; + if(mode == DirectA) return { name, " $", hex<2>(pl), ",a" }; + if(mode == IXA) return { name, " (x),a" }; + if(mode == IDirectXA) return { name, " ($", hex<2>(pl), "+x),a" }; + if(mode == XConstant) return { name, " x,#$", hex<2>(pl) }; + if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" }; + if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" }; + if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" }; + if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" }; + if(mode == Ya) return { name, " ya" }; + if(mode == DirectXA) return { name, " $", hex<2>(pl), "+x,a" }; + if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" }; + if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" }; + if(mode == IDirectYA) return { name, " ($", hex<2>(pl), ")+y,a" }; + if(mode == DirectYX) return { name, " $", hex<2>(pl), "+y,x" }; + if(mode == DirectYa) return { name, " $", hex<2>(pl), ",ya" }; + if(mode == DirectXY) return { name, " $", hex<2>(pl), "+x,y" }; + if(mode == AY) return { name, " a,y" }; + if(mode == DirectXRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; + if(mode == XDirectY) return { name, " x,$", hex<2>(pl), "+y" }; + if(mode == YDirectX) return { name, " y,$", hex<2>(pl), "+x" }; + if(mode == YA) return { name, " y,a" }; + if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) }; + + return ""; +} + +inline string SNESSMP::disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph) { + string name = opcodeInfo[opcode].name; + unsigned mode = opcodeInfo[opcode].mode; + unsigned pdl = (p << 8) + pl; + unsigned pdh = (p << 8) + ph; + unsigned pa = (ph << 8) + pl; + + if(mode == Implied) return name; + if(mode == TVector) return { name, " ", opcode >> 4 }; + if(mode == Direct) return { name, " $", hex<3>(pdl) }; + if(mode == DirectRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; + if(mode == ADirect) return { name, " a,$", hex<3>(pdl) }; + if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) }; + if(mode == AIX) return { name, "a,(x)" }; + if(mode == AIDirectX) return { name, " a,($", hex<3>(pdl), "+x)" }; + if(mode == AConstant) return { name, " a,#$", hex<2>(pl) }; + if(mode == DirectDirect) return { name, " $", hex<3>(pdh), ",$", hex<3>(pdl) }; + if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; + if(mode == Absolute) return { name, " $", hex<4>(pa) }; + if(mode == P) return { name, " p" }; + if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" }; + if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) }; + if(mode == ADirectX) return { name, " a,$", hex<3>(pdl), "+x" }; + if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" }; + if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" }; + if(mode == AIDirectY) return { name, " a,($", hex<3>(pdl), ")+y" }; + if(mode == DirectConstant) return { name, " $", hex<3>(pdh), ",#$", hex<2>(pl) }; + if(mode == IXIY) return { name, " (x),(y)" }; + if(mode == DirectX) return { name, " $", hex<3>(pdl), "+x" }; + if(mode == A) return { name, " a" }; + if(mode == X) return { name, " x" }; + if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) }; + if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" }; + if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 }; + if(mode == XDirect) return { name, " x,$", hex<3>(pdl) }; + if(mode == PVector) return { name, " $ff", hex<2>(pl) }; + if(mode == YaDirect) return { name, " ya,$", hex<3>(pdl) }; + if(mode == XA) return { name, " x,a" }; + if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) }; + if(mode == Y) return { name, " y" }; + if(mode == AX) return { name, " a,x" }; + if(mode == YDirect) return { name, " y,$", hex<3>(pdl) }; + if(mode == YConstant) return { name, " y,#$", hex<2>(pl) }; + if(mode == XSp) return { name, " x,sp" }; + if(mode == YaX) return { name, " ya,x" }; + if(mode == IXPA) return { name, " (x)+,a" }; + if(mode == SpX) return { name, " sp,x" }; + if(mode == AIXP) return { name, " a,(x)+" }; + if(mode == DirectA) return { name, " $", hex<3>(pdl), ",a" }; + if(mode == IXA) return { name, " (x),a" }; + if(mode == IDirectXA) return { name, " ($", hex<3>(pdl), "+x),a" }; + if(mode == XConstant) return { name, " x,#$", hex<2>(pl) }; + if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" }; + if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" }; + if(mode == DirectY) return { name, " $", hex<3>(pdl), ",y" }; + if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" }; + if(mode == Ya) return { name, " ya" }; + if(mode == DirectXA) return { name, " $", hex<3>(pdl), "+x,a" }; + if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" }; + if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" }; + if(mode == IDirectYA) return { name, " ($", hex<3>(pdl), ")+y,a" }; + if(mode == DirectYX) return { name, " $", hex<3>(pdl), "+y,x" }; + if(mode == DirectYa) return { name, " $", hex<3>(pdl), ",ya" }; + if(mode == DirectXY) return { name, " $", hex<3>(pdl), "+x,y" }; + if(mode == AY) return { name, " a,y" }; + if(mode == DirectXRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) }; + if(mode == XDirectY) return { name, " x,$", hex<3>(pdl), "+y" }; + if(mode == YDirectX) return { name, " y,$", hex<3>(pdl), "+x" }; + if(mode == YA) return { name, " y,a" }; + if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) }; + + return ""; +} + +} + +#endif diff --git a/nall/sort.hpp b/nall/sort.hpp new file mode 100755 index 00000000..23c317a5 --- /dev/null +++ b/nall/sort.hpp @@ -0,0 +1,62 @@ +#ifndef NALL_SORT_HPP +#define NALL_SORT_HPP + +#include + +//class: merge sort +//average: O(n log n) +//worst: O(n log n) +//memory: O(n) +//stack: O(log n) +//stable?: yes + +//notes: +//there are two primary reasons for choosing merge sort +//over the (usually) faster quick sort*: +//1: it is a stable sort. +//2: it lacks O(n^2) worst-case overhead. +//(* which is also O(n log n) in the average case.) + +namespace nall { + template + void sort(T list[], unsigned length) { + if(length <= 1) return; //nothing to sort + + //use insertion sort to quickly sort smaller blocks + if(length < 64) { + for(unsigned i = 0; i < length; i++) { + unsigned min = i; + for(unsigned j = i + 1; j < length; j++) { + if(list[j] < list[min]) min = j; + } + if(min != i) swap(list[i], list[min]); + } + return; + } + + //split list in half and recursively sort both + unsigned middle = length / 2; + sort(list, middle); + sort(list + middle, length - middle); + + //left and right are sorted here; perform merge sort + T *buffer = new T[length]; + unsigned offset = 0; + unsigned left = 0; + unsigned right = middle; + while(left < middle && right < length) { + if(list[left] < list[right]) { + buffer[offset++] = list[left++]; + } else { + buffer[offset++] = list[right++]; + } + } + while(left < middle) buffer[offset++] = list[left++]; + while(right < length) buffer[offset++] = list[right++]; + + for(unsigned i = 0; i < length; i++) list[i] = buffer[i]; + delete[] buffer; + } +} + +#endif diff --git a/nall/stack.hpp b/nall/stack.hpp new file mode 100755 index 00000000..fe8e16a1 --- /dev/null +++ b/nall/stack.hpp @@ -0,0 +1,26 @@ +#ifndef NALL_STACK_HPP +#define NALL_STACK_HPP + +#include + +namespace nall { + template struct stack : public linear_vector { + void push(const T &value) { + linear_vector::append(value); + } + + T pull() { + if(linear_vector::size() == 0) throw; + T value = linear_vector::operator[](linear_vector::size() - 1); + linear_vector::remove(linear_vector::size() - 1); + return value; + } + + T& operator()() { + if(linear_vector::size() == 0) throw; + return linear_vector::operator[](linear_vector::size() - 1); + } + }; +} + +#endif diff --git a/nall/static.hpp b/nall/static.hpp new file mode 100755 index 00000000..4acb9fd0 --- /dev/null +++ b/nall/static.hpp @@ -0,0 +1,20 @@ +#ifndef NALL_STATIC_HPP +#define NALL_STATIC_HPP + +namespace nall { + template struct static_if { typedef T type; }; + template struct static_if { typedef F type; }; + template struct mp_static_if { typedef typename static_if::type type; }; + + template struct static_and { enum { value = false }; }; + template<> struct static_and { enum { value = true }; }; + template struct mp_static_and { enum { value = static_and::value }; }; + + template struct static_or { enum { value = false }; }; + template<> struct static_or { enum { value = true }; }; + template<> struct static_or { enum { value = true }; }; + template<> struct static_or { enum { value = true }; }; + template struct mp_static_or { enum { value = static_or::value }; }; +} + +#endif diff --git a/nall/stdint.hpp b/nall/stdint.hpp new file mode 100755 index 00000000..d8b6c788 --- /dev/null +++ b/nall/stdint.hpp @@ -0,0 +1,44 @@ +#ifndef NALL_STDINT_HPP +#define NALL_STDINT_HPP + +#include + +#if defined(_MSC_VER) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef signed long long int64_t; + typedef int64_t intmax_t; + #if defined(_WIN64) + typedef int64_t intptr_t; + #else + typedef int32_t intptr_t; + #endif + + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + typedef unsigned long long uint64_t; + typedef uint64_t uintmax_t; + #if defined(_WIN64) + typedef uint64_t uintptr_t; + #else + typedef uint32_t uintptr_t; + #endif +#else + #include +#endif + +namespace nall { + static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" ); + static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size"); + static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size"); + static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size"); + + static_assert(sizeof(uint8_t) == 1, "int8_t is not of the correct size" ); + static_assert(sizeof(uint16_t) == 2, "int16_t is not of the correct size"); + static_assert(sizeof(uint32_t) == 4, "int32_t is not of the correct size"); + static_assert(sizeof(uint64_t) == 8, "int64_t is not of the correct size"); +} + +#endif diff --git a/nall/string.hpp b/nall/string.hpp new file mode 100755 index 00000000..2341911c --- /dev/null +++ b/nall/string.hpp @@ -0,0 +1,46 @@ +#ifndef NALL_STRING_HPP +#define NALL_STRING_HPP + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NALL_STRING_INTERNAL_HPP +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef NALL_STRING_INTERNAL_HPP + +#endif diff --git a/nall/string/base.hpp b/nall/string/base.hpp new file mode 100755 index 00000000..ede21ff6 --- /dev/null +++ b/nall/string/base.hpp @@ -0,0 +1,195 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + struct cstring; + struct string; + struct lstring; + template inline const char* to_string(T); + + struct cstring { + inline operator const char*() const; + inline unsigned length() const; + inline bool operator==(const char*) const; + inline bool operator!=(const char*) const; + inline optional position(const char *key) const; + inline optional iposition(const char *key) const; + inline cstring& operator=(const char *data); + inline cstring(const char *data); + inline cstring(); + + protected: + const char *data; + }; + + struct string { + inline void reserve(unsigned); + + template inline string& assign(Args&&... args); + template inline string& append(Args&&... args); + + inline bool readfile(const string&); + + template inline string& replace(const char*, const char*); + template inline string& ireplace(const char*, const char*); + template inline string& qreplace(const char*, const char*); + template inline string& iqreplace(const char*, const char*); + + inline unsigned length() const; + + template inline lstring split(const char*) const; + template inline lstring isplit(const char*) const; + template inline lstring qsplit(const char*) const; + template inline lstring iqsplit(const char*) const; + + 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; + inline bool ibeginswith(const char*) const; + inline bool endswith(const char*) const; + inline bool iendswith(const char*) const; + + inline string& lower(); + inline string& upper(); + inline string& qlower(); + inline string& qupper(); + inline string& transform(const char *before, const char *after); + + template inline string& ltrim(const char *key = " "); + template inline string& rtrim(const char *key = " "); + template inline string& trim(const char *key = " ", const char *rkey = 0); + + inline optional position(const char *key) const; + inline optional iposition(const char *key) const; + inline optional qposition(const char *key) const; + inline optional iqposition(const char *key) const; + + inline operator const char*() const; + inline char* operator()(); + inline char& operator[](int); + + inline bool operator==(const char*) const; + inline bool operator!=(const char*) const; + inline bool operator< (const char*) const; + inline bool operator<=(const char*) const; + inline bool operator> (const char*) const; + inline bool operator>=(const char*) const; + + inline string& operator=(const string&); + inline string& operator=(string&&); + + template inline string(Args&&... args); + inline string(const string&); + inline string(string&&); + inline ~string(); + + inline char* begin() { return &data[0]; } + inline char* end() { return &data[length()]; } + inline const char* begin() const { return &data[0]; } + inline const char* end() const { return &data[length()]; } + + //internal functions + inline string& assign_(const char*); + inline string& append_(const char*); + + protected: + char *data; + unsigned size; + + template inline string& ureplace(const char*, const char*); + + #if defined(QSTRING_H) + public: + inline operator QString() const; + #endif + }; + + struct lstring : vector { + inline optional find(const char*) const; + template inline lstring& split(const char*, const char*); + template inline lstring& isplit(const char*, const char*); + template inline lstring& qsplit(const char*, const char*); + template inline lstring& iqsplit(const char*, const char*); + + inline bool operator==(const lstring&) const; + inline bool operator!=(const lstring&) const; + + inline lstring(); + inline lstring(std::initializer_list); + + protected: + template inline lstring& usplit(const char*, const char*); + }; + + //compare.hpp + inline char chrlower(char c); + inline char chrupper(char c); + inline int istrcmp(const char *str1, const char *str2); + inline bool wildcard(const char *str, const char *pattern); + inline bool iwildcard(const char *str, const char *pattern); + inline bool strbegin(const char *str, const char *key); + inline bool istrbegin(const char *str, const char *key); + inline bool strend(const char *str, const char *key); + inline bool istrend(const char *str, const char *key); + + //convert.hpp + inline char* strlower(char *str); + inline char* strupper(char *str); + inline char* qstrlower(char *str); + inline char* qstrupper(char *str); + inline char* strtr(char *dest, const char *before, const char *after); + + //math.hpp + inline bool strint(const char *str, int &result); + inline bool strmath(const char *str, int &result); + + //platform.hpp + inline string realpath(const char *name); + inline string userpath(); + inline string currentpath(); + + //strl.hpp + inline unsigned strlcpy(char *dest, const char *src, unsigned length); + inline unsigned strlcat(char *dest, const char *src, unsigned length); + + //strpos.hpp + inline optional strpos(const char *str, const char *key); + inline optional istrpos(const char *str, const char *key); + inline optional qstrpos(const char *str, const char *key); + inline optional iqstrpos(const char *str, const char *key); + template inline optional ustrpos(const char *str, const char *key); + + //trim.hpp + template inline char* ltrim(char *str, const char *key = " "); + template inline char* rtrim(char *str, const char *key = " "); + template inline char* trim(char *str, const char *key = " ", const char *rkey = 0); + + //utility.hpp + template alwaysinline bool chrequal(char x, char y); + template alwaysinline bool quoteskip(T *&p); + template alwaysinline bool quotecopy(char *&t, T *&p); + inline unsigned strlcpy(string &dest, const char *src, unsigned length); + inline unsigned strlcat(string &dest, const char *src, unsigned length); + inline string substr(const char *src, unsigned start = 0, unsigned length = ~0u); + inline string sha256(const uint8_t *data, unsigned size); + + inline char* integer(char *result, intmax_t value); + inline char* decimal(char *result, uintmax_t value); + + template inline string integer(intmax_t value); + template inline string linteger(intmax_t value); + template inline string decimal(uintmax_t value); + template inline string ldecimal(uintmax_t value); + template inline string hex(uintmax_t value); + template inline string binary(uintmax_t value); + inline unsigned fp(char *str, double value); + inline string fp(double value); + + //variadic.hpp + template inline void print(Args&&... args); +}; + +#endif diff --git a/nall/string/bml.hpp b/nall/string/bml.hpp new file mode 100755 index 00000000..4f8139cc --- /dev/null +++ b/nall/string/bml.hpp @@ -0,0 +1,151 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +//BML v1.0 parser +//revision 0.05 + +namespace nall { +namespace BML { + +inline static string indent(const char *s, unsigned depth) { + array output; + do { + for(unsigned n = 0; n < depth; n++) output.append('\t'); + do output.append(*s); while(*s && *s++ != '\n'); + } while(*s); + return output.get(); +} + +struct Node { + cstring name; + cstring value; + +private: + linear_vector children; + + inline bool valid(char p) const { //A-Za-z0-9-. + return p - 'A' < 26u | p - 'a' < 26u | p - '0' < 10u | p - '-' < 2u; + } + + inline unsigned parseDepth(char *&p) { + while(*p == '\n' || *p == '#') { + while(*p != '\n') *p++ = 0; + *p++ = 0; //'\n' + } + unsigned depth = 0; + while(p[depth] == '\t') depth++; + return depth; + } + + inline void parseName(char *&p) { + if(valid(*p) == false) throw "Missing node name"; + name = p; + while(valid(*p)) p++; + } + + inline void parseValue(char *&p) { + char terminal = *p == ':' ? '\n' : ' '; //':' or '=' + *p++ = 0; + value = p; + while(*p && *p != terminal && *p != '\n') p++; + } + + inline void parseBlock(char *&p, unsigned depth) { + value = p; + char *w = p; + while(parseDepth(p) > depth) { + p += depth + 1; + while(*p && *p != '\n') *w++ = *p++; + if(*p && *p != '\n') throw "Multi-line value missing line feed"; + *w++ = *p; + } + *(w - 1) = 0; //'\n' + } + + inline void parseLine(char *&p) { + unsigned depth = parseDepth(p); + while(*p == '\t') p++; + + parseName(p); + bool multiLine = *p == '~'; + if(multiLine) *p++ = 0; + else if(*p == ':' || *p == '=') parseValue(p); + if(*p && *p != ' ' && *p != '\n') throw "Invalid character encountered"; + + while(*p == ' ') { + *p++ = 0; + Node node; + node.parseName(p); + if(*p == ':' || *p == '=') node.parseValue(p); + if(*p && *p != ' ' && *p != '\n') throw "Invalid character after node"; + if(*p == '\n') *p++ = 0; + children.append(node); + } + + if(multiLine) return parseBlock(p, depth); + + while(parseDepth(p) > depth) { + Node node; + node.parseLine(p); + children.append(node); + } + } + + inline void parse(char *&p) { + while(*p) { + Node node; + node.parseLine(p); + children.append(node); + } + } + +public: + inline Node& operator[](const char *name) { + for(auto &node : children) { + if(node.name == name) return node; + } + static Node node; + node.name = nullptr; + return node; + } + + inline bool exists() const { return name; } + unsigned size() const { return children.size(); } + Node* begin() { return children.begin(); } + Node* end() { return children.end(); } + const Node* begin() const { return children.begin(); } + const Node* end() const { return children.end(); } + inline Node() : name(""), value("") {} + friend class Document; +}; + +struct Document : Node { + cstring error; + + inline bool load(const char *document) { + if(document == nullptr) return false; + this->document = strdup(document); + char *p = this->document; + try { + this->error = nullptr; + parse(p); + } catch(const char *error) { + this->error = error; + free(this->document); + this->document = nullptr; + children.reset(); + return false; + } + return true; + } + + inline Document(const char *document = "") : document(nullptr), error(nullptr) { if(*document) load(document); } + inline ~Document() { if(document) free(document); } + +private: + char *document; +}; + +} +} + +#endif diff --git a/nall/string/bsv.hpp b/nall/string/bsv.hpp new file mode 100755 index 00000000..d9415d53 --- /dev/null +++ b/nall/string/bsv.hpp @@ -0,0 +1,76 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +//BSV v1.0 parser +//revision 0.02 + +namespace nall { + +struct BSV { + static inline string decode(const char *input) { + string output; + unsigned offset = 0; + while(*input) { + //illegal characters + if(*input == '}' ) return ""; + if(*input == '\r') return ""; + if(*input == '\n') return ""; + + //normal characters + if(*input != '{') { output[offset++] = *input++; continue; } + + //entities + if(strbegin(input, "{lf}")) { output[offset++] = '\n'; input += 4; continue; } + if(strbegin(input, "{lb}")) { output[offset++] = '{'; input += 4; continue; } + if(strbegin(input, "{rb}")) { output[offset++] = '}'; input += 4; continue; } + + //illegal entities + return ""; + } + output[offset] = 0; + return output; + } + + static inline string encode(const char *input) { + string output; + unsigned offset = 0; + while(*input) { + //illegal characters + if(*input == '\r') return ""; + + if(*input == '\n') { + output[offset++] = '{'; + output[offset++] = 'l'; + output[offset++] = 'f'; + output[offset++] = '}'; + input++; + continue; + } + + if(*input == '{') { + output[offset++] = '{'; + output[offset++] = 'l'; + output[offset++] = 'b'; + output[offset++] = '}'; + input++; + continue; + } + + if(*input == '}') { + output[offset++] = '{'; + output[offset++] = 'r'; + output[offset++] = 'b'; + output[offset++] = '}'; + input++; + continue; + } + + output[offset++] = *input++; + } + output[offset] = 0; + return output; + } +}; + +} + +#endif diff --git a/nall/string/cast.hpp b/nall/string/cast.hpp new file mode 100755 index 00000000..452b6bec --- /dev/null +++ b/nall/string/cast.hpp @@ -0,0 +1,40 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +//this is needed, as C++0x does not support explicit template specialization inside classes +template<> inline const char* to_string(bool v) { return v ? "true" : "false"; } +template<> inline const char* to_string(char v) { static char temp[256]; return integer(temp, v); } + +template<> inline const char* to_string (signed char v) { static char temp[256]; return integer(temp, v); } +template<> inline const char* to_string (signed short v) { static char temp[256]; return integer(temp, v); } +template<> inline const char* to_string (signed int v) { static char temp[256]; return integer(temp, v); } +template<> inline const char* to_string (signed long v) { static char temp[256]; return integer(temp, v); } +template<> inline const char* to_string(signed long long v) { static char temp[256]; return integer(temp, v); } + +template<> inline const char* to_string (unsigned char v) { static char temp[256]; return decimal(temp, v); } +template<> inline const char* to_string (unsigned short v) { static char temp[256]; return decimal(temp, v); } +template<> inline const char* to_string (unsigned int v) { static char temp[256]; return decimal(temp, v); } +template<> inline const char* to_string (unsigned long v) { static char temp[256]; return decimal(temp, v); } +template<> inline const char* to_string(unsigned long long v) { static char temp[256]; return decimal(temp, v); } + +template<> inline const char* to_string (float v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; } +template<> inline const char* to_string (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; } +template<> inline const char* to_string(long double v) { static char temp[256]; snprintf(temp, 255, "%Lf", v); return temp; } + +template<> inline const char* to_string (char *v) { return v; } +template<> inline const char* to_string (const char *v) { return v; } +template<> inline const char* to_string (string v) { return v; } +template<> inline const char* to_string (const string &v) { return v; } +template<> inline const char* to_string (cstring v) { return v; } +template<> inline const char* to_string(const cstring &v) { return v; } + +#if defined(QSTRING_H) +template<> inline const char* to_string(QString v) { return v.toUtf8().constData(); } +template<> inline const char* to_string(const QString &v) { return v.toUtf8().constData(); } +string::operator QString() const { return QString::fromUtf8(*this); } +#endif + +} + +#endif diff --git a/nall/string/compare.hpp b/nall/string/compare.hpp new file mode 100755 index 00000000..ce0af487 --- /dev/null +++ b/nall/string/compare.hpp @@ -0,0 +1,109 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +char chrlower(char c) { + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; +} + +char chrupper(char c) { + return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c; +} + +int istrcmp(const char *str1, const char *str2) { + while(*str1) { + if(chrlower(*str1) != chrlower(*str2)) break; + str1++, str2++; + } + return (int)chrlower(*str1) - (int)chrlower(*str2); +} + +bool wildcard(const char *s, const char *p) { + const char *cp = 0, *mp = 0; + while(*s && *p != '*') { + if(*p != '?' && *s != *p) return false; + p++, s++; + } + while(*s) { + if(*p == '*') { + if(!*++p) return true; + mp = p, cp = s + 1; + } else if(*p == '?' || *p == *s) { + p++, s++; + } else { + p = mp, s = cp++; + } + } + while(*p == '*') p++; + return !*p; +} + +bool iwildcard(const char *s, const char *p) { + const char *cp = 0, *mp = 0; + while(*s && *p != '*') { + if(*p != '?' && chrlower(*s) != chrlower(*p)) return false; + p++, s++; + } + while(*s) { + if(*p == '*') { + if(!*++p) return true; + mp = p, cp = s + 1; + } else if(*p == '?' || chrlower(*p) == chrlower(*s)) { + p++, s++; + } else { + p = mp, s = cp++; + } + } + while(*p == '*') p++; + return !*p; +} + +bool strbegin(const char *str, const char *key) { + int i, ssl = strlen(str), ksl = strlen(key); + + if(ksl > ssl) return false; + return (!memcmp(str, key, ksl)); +} + +bool istrbegin(const char *str, const char *key) { + int ssl = strlen(str), ksl = strlen(key); + + if(ksl > ssl) return false; + for(int i = 0; i < ksl; i++) { + if(str[i] >= 'A' && str[i] <= 'Z') { + if(str[i] != key[i] && str[i]+0x20 != key[i])return false; + } else if(str[i] >= 'a' && str[i] <= 'z') { + if(str[i] != key[i] && str[i]-0x20 != key[i])return false; + } else { + if(str[i] != key[i])return false; + } + } + return true; +} + +bool strend(const char *str, const char *key) { + int ssl = strlen(str), ksl = strlen(key); + + if(ksl > ssl) return false; + return (!memcmp(str + ssl - ksl, key, ksl)); +} + +bool istrend(const char *str, const char *key) { + int ssl = strlen(str), ksl = strlen(key); + + if(ksl > ssl) return false; + for(int i = ssl - ksl, z = 0; i < ssl; i++, z++) { + if(str[i] >= 'A' && str[i] <= 'Z') { + if(str[i] != key[z] && str[i]+0x20 != key[z])return false; + } else if(str[i] >= 'a' && str[i] <= 'z') { + if(str[i] != key[z] && str[i]-0x20 != key[z])return false; + } else { + if(str[i] != key[z])return false; + } + } + return true; +} + +} + +#endif diff --git a/nall/string/convert.hpp b/nall/string/convert.hpp new file mode 100755 index 00000000..f5a2a780 --- /dev/null +++ b/nall/string/convert.hpp @@ -0,0 +1,64 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +char* strlower(char *str) { + if(!str) return 0; + int i = 0; + while(str[i]) { + str[i] = chrlower(str[i]); + i++; + } + return str; +} + +char* strupper(char *str) { + if(!str) return 0; + int i = 0; + while(str[i]) { + str[i] = chrupper(str[i]); + i++; + } + return str; +} + +char* qstrlower(char *s) { + if(!s) return 0; + bool quoted = false; + while(*s) { + if(*s == '\"' || *s == '\'') quoted ^= 1; + if(quoted == false && *s >= 'A' && *s <= 'Z') *s += 0x20; + s++; + } +} + +char* qstrupper(char *s) { + if(!s) return 0; + bool quoted = false; + while(*s) { + if(*s == '\"' || *s == '\'') quoted ^= 1; + if(quoted == false && *s >= 'a' && *s <= 'z') *s -= 0x20; + s++; + } +} + +char* strtr(char *dest, const char *before, const char *after) { + if(!dest || !before || !after) return dest; + int sl = strlen(dest), bsl = strlen(before), asl = strlen(after); + + if(bsl != asl || bsl == 0) return dest; //patterns must be the same length for 1:1 replace + for(unsigned i = 0; i < sl; i++) { + for(unsigned l = 0; l < bsl; l++) { + if(dest[i] == before[l]) { + dest[i] = after[l]; + break; + } + } + } + + return dest; +} + +} + +#endif diff --git a/nall/string/core.hpp b/nall/string/core.hpp new file mode 100755 index 00000000..95a778a6 --- /dev/null +++ b/nall/string/core.hpp @@ -0,0 +1,159 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +static void istring(string &output) { +} + +template +static void istring(string &output, const T &value, Args&&... args) { + output.append_(to_string(value)); + istring(output, std::forward(args)...); +} + +void string::reserve(unsigned size_) { + if(size_ > size) { + size = size_; + data = (char*)realloc(data, size + 1); + data[size] = 0; + } +} + +template string& string::assign(Args&&... args) { + *data = 0; + istring(*this, std::forward(args)...); + return *this; +} + +template string& string::append(Args&&... args) { + istring(*this, std::forward(args)...); + return *this; +} + +string& string::assign_(const char *s) { + unsigned length = strlen(s); + reserve(length); + strcpy(data, s); + return *this; +} + +string& string::append_(const char *s) { + unsigned length = strlen(data) + strlen(s); + reserve(length); + strcat(data, s); + return *this; +} + +string::operator const char*() const { + return data; +} + +char* string::operator()() { + return data; +} + +char& string::operator[](int index) { + reserve(index); + return data[index]; +} + +bool string::operator==(const char *str) const { return strcmp(data, str) == 0; } +bool string::operator!=(const char *str) const { return strcmp(data, str) != 0; } +bool string::operator< (const char *str) const { return strcmp(data, str) < 0; } +bool string::operator<=(const char *str) const { return strcmp(data, str) <= 0; } +bool string::operator> (const char *str) const { return strcmp(data, str) > 0; } +bool string::operator>=(const char *str) const { return strcmp(data, str) >= 0; } + +string& string::operator=(const string &value) { + if(&value == this) return *this; + assign(value); + return *this; +} + +string& string::operator=(string &&source) { + if(&source == this) return *this; + if(data) free(data); + size = source.size; + data = source.data; + source.data = nullptr; + source.size = 0; + return *this; +} + +template string::string(Args&&... args) { + size = 64; + data = (char*)malloc(size + 1); + *data = 0; + istring(*this, std::forward(args)...); +} + +string::string(const string &value) { + if(&value == this) return; + size = strlen(value); + data = strdup(value); +} + +string::string(string &&source) { + if(&source == this) return; + size = source.size; + data = source.data; + source.data = nullptr; +} + +string::~string() { + if(data) free(data); +} + +bool string::readfile(const string &filename) { + assign(""); + + #if !defined(_WIN32) + FILE *fp = fopen(filename, "rb"); + #else + FILE *fp = _wfopen(utf16_t(filename), L"rb"); + #endif + if(!fp) return false; + + fseek(fp, 0, SEEK_END); + unsigned size = ftell(fp); + rewind(fp); + char *fdata = new char[size + 1]; + unsigned unused = fread(fdata, 1, size, fp); + fclose(fp); + fdata[size] = 0; + assign(fdata); + delete[] fdata; + + return true; +} + +optional lstring::find(const char *key) const { + for(unsigned i = 0; i < size(); i++) { + if(operator[](i) == key) return { true, i }; + } + return { false, 0 }; +} + +bool lstring::operator==(const lstring &source) const { + if(this == &source) return true; + if(size() != source.size()) return false; + for(unsigned n = 0; n < size(); n++) { + if(operator[](n) != source[n]) return false; + } + return true; +} + +bool lstring::operator!=(const lstring &source) const { + return !operator==(source); +} + +inline lstring::lstring() { +} + +inline lstring::lstring(std::initializer_list list) { + for(auto &data : list) append(data); +} + +} + +#endif diff --git a/nall/string/cstring.hpp b/nall/string/cstring.hpp new file mode 100755 index 00000000..13b508ff --- /dev/null +++ b/nall/string/cstring.hpp @@ -0,0 +1,21 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +//const string: +//bind a const char* pointer to an object that has various testing functionality; +//yet lacks the memory allocation and modification functionality of the string class + +namespace nall { + +cstring::operator const char*() const { return data; } +unsigned cstring::length() const { return strlen(data); } +bool cstring::operator==(const char *s) const { return !strcmp(data, s); } +bool cstring::operator!=(const char *s) const { return strcmp(data, s); } +optional cstring::position (const char *key) const { return strpos(data, key); } +optional cstring::iposition(const char *key) const { return istrpos(data, key); } +cstring& cstring::operator=(const char *data) { this->data = data; return *this; } +cstring::cstring(const char *data) : data(data) {} +cstring::cstring() : data("") {} + +} + +#endif diff --git a/nall/string/filename.hpp b/nall/string/filename.hpp new file mode 100755 index 00000000..6dea67fc --- /dev/null +++ b/nall/string/filename.hpp @@ -0,0 +1,62 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +// "foo/bar.c" -> "foo/" +// "foo/" -> "foo/" +// "bar.c" -> "./" +inline string dir(char const *name) { + string result = name; + for(signed i = strlen(result); i >= 0; i--) { + if(result[i] == '/' || result[i] == '\\') { + result[i + 1] = 0; + break; + } + if(i == 0) result = "./"; + } + return result; +} + +// "foo/bar.c" -> "bar.c" +inline string notdir(char const *name) { + for(signed i = strlen(name); i >= 0; i--) { + if(name[i] == '/' || name[i] == '\\') { + name += i + 1; + break; + } + } + string result = name; + return result; +} + +// "foo/bar.c" -> "foo/bar" +inline string basename(char const *name) { + string result = name; + for(signed i = strlen(result); i >= 0; i--) { + if(result[i] == '/' || result[i] == '\\') { + //file has no extension + break; + } + if(result[i] == '.') { + result[i] = 0; + break; + } + } + return result; +} + +// "foo/bar.c" -> "c" +inline string extension(char const *name) { + for(signed i = strlen(name); i >= 0; i--) { + if(name[i] == '.') { + name += i + 1; + break; + } + } + string result = name; + return result; +} + +} + +#endif diff --git a/nall/string/math.hpp b/nall/string/math.hpp new file mode 100755 index 00000000..bbe8e87d --- /dev/null +++ b/nall/string/math.hpp @@ -0,0 +1,167 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +static function eval_fallback; + +static int eval_integer(const char *&s) { + if(!*s) throw "unrecognized_integer"; + int value = 0, x = *s, y = *(s + 1); + + //hexadecimal + if(x == '0' && (y == 'X' || y == 'x')) { + s += 2; + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; } + if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; } + if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; } + return value; + } + } + + //binary + if(x == '0' && (y == 'B' || y == 'b')) { + s += 2; + while(true) { + if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; } + return value; + } + } + + //octal (or decimal '0') + if(x == '0') { + s += 1; + while(true) { + if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; } + return value; + } + } + + //decimal + if(x >= '0' && x <= '9') { + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; } + return value; + } + } + + //char + if(x == '\'' && y != '\'') { + s += 1; + while(true) { + value = value * 256 + *s++; + if(*s == '\'') { s += 1; return value; } + if(!*s) throw "mismatched_char"; + } + } + + throw "unrecognized_integer"; +} + +static int eval(const char *&s, int depth = 0) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) throw "unrecognized_token"; + int value = 0, x = *s, y = *(s + 1); + + if(*s == '(') { + value = eval(++s, 1); + if(*s++ != ')') throw "mismatched_group"; + } + + else if(x == '!') value = !eval(++s, 13); + else if(x == '~') value = ~eval(++s, 13); + else if(x == '+') value = +eval(++s, 13); + else if(x == '-') value = -eval(++s, 13); + + else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s); + + else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing + + else throw "unrecognized_token"; + + while(true) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) break; + x = *s, y = *(s + 1); + + if(depth >= 13) break; + if(x == '*') { value *= eval(++s, 13); continue; } + if(x == '/') { value /= eval(++s, 13); continue; } + if(x == '%') { value %= eval(++s, 13); continue; } + + if(depth >= 12) break; + if(x == '+') { value += eval(++s, 12); continue; } + if(x == '-') { value -= eval(++s, 12); continue; } + + if(depth >= 11) break; + if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; } + if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; } + + if(depth >= 10) break; + if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; } + if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; } + if(x == '<') { value = value < eval(++s, 10); continue; } + if(x == '>') { value = value > eval(++s, 10); continue; } + + if(depth >= 9) break; + if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; } + if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; } + + if(depth >= 8) break; + if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; } + + if(depth >= 7) break; + if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; } + + if(depth >= 6) break; + if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; } + + if(depth >= 5) break; + if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; } + + if(depth >= 4) break; + if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; } + + if(depth >= 3) break; + if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; } + + if(x == '?') { + int lhs = eval(++s, 2); + if(*s != ':') throw "mismatched_ternary"; + int rhs = eval(++s, 2); + value = value ? lhs : rhs; + continue; + } + if(depth >= 2) break; + + if(depth > 0 && x == ')') break; + + throw "unrecognized_token"; + } + + return value; +} + +bool strint(const char *s, int &result) { + try { + result = eval_integer(s); + return true; + } catch(const char*) { + result = 0; + return false; + } +} + +bool strmath(const char *s, int &result) { + try { + result = eval(s); + return true; + } catch(const char*) { + result = 0; + return false; + } +} + +} + +#endif diff --git a/nall/string/platform.hpp b/nall/string/platform.hpp new file mode 100755 index 00000000..83a5fbae --- /dev/null +++ b/nall/string/platform.hpp @@ -0,0 +1,39 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +string currentpath() { + char path[PATH_MAX]; + if(::getcwd(path)) { + string result(path); + result.transform("\\", "/"); + if(result.endswith("/") == false) result.append("/"); + return result; + } + return "./"; +} + +string userpath() { + char path[PATH_MAX]; + if(::userpath(path)) { + string result(path); + result.transform("\\", "/"); + if(result.endswith("/") == false) result.append("/"); + return result; + } + return currentpath(); +} + +string realpath(const char *name) { + char path[PATH_MAX]; + if(::realpath(name, path)) { + string result(path); + result.transform("\\", "/"); + return result; + } + return userpath(); +} + +} + +#endif diff --git a/nall/string/replace.hpp b/nall/string/replace.hpp new file mode 100755 index 00000000..2bd1412f --- /dev/null +++ b/nall/string/replace.hpp @@ -0,0 +1,51 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +template +string& string::ureplace(const char *key, const char *token) { + if(!key || !*key) return *this; + enum : unsigned { limit = Limit ? Limit : ~0u }; + + const char *p = data; + unsigned counter = 0, keyLength = 0; + + while(*p) { + if(quoteskip(p)) continue; + for(unsigned n = 0;; n++) { + if(key[n] == 0) { counter++; p += n; keyLength = n; break; } + if(!chrequal(key[n], p[n])) { p++; break; } + } + } + if(counter == 0) return *this; + if(Limit) counter = min(counter, Limit); + + char *t = data, *base; + unsigned tokenLength = strlen(token); + if(tokenLength > keyLength) { + t = base = strdup(data); + reserve((unsigned)(p - data) + ((tokenLength - keyLength) * counter)); + } + char *o = data; + + while(*t && counter) { + if(quotecopy(o, t)) continue; + for(unsigned n = 0;; n++) { + if(key[n] == 0) { counter--; memcpy(o, token, tokenLength); t += keyLength; o += tokenLength; break; } + if(!chrequal(key[n], t[n])) { *o++ = *t++; break; } + } + } + do *o++ = *t; while(*t++); + if(tokenLength > keyLength) free(base); + + return *this; +} + +template string &string::replace(const char *key, const char *token) { return ureplace(key, token); } +template string &string::ireplace(const char *key, const char *token) { return ureplace(key, token); } +template string &string::qreplace(const char *key, const char *token) { return ureplace(key, token); } +template string &string::iqreplace(const char *key, const char *token) { return ureplace(key, token); } + +}; + +#endif diff --git a/nall/string/split.hpp b/nall/string/split.hpp new file mode 100755 index 00000000..bb12a91b --- /dev/null +++ b/nall/string/split.hpp @@ -0,0 +1,36 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +template lstring& lstring::usplit(const char *key, const char *base) { + reset(); + if(!key || !*key) return *this; + + const char *p = base; + + while(*p) { + if(Limit) if(size() >= Limit) break; + if(quoteskip(p)) continue; + for(unsigned n = 0;; n++) { + if(key[n] == 0) { + append(substr(base, 0, p - base)); + p += n; + base = p; + break; + } + if(!chrequal(key[n], p[n])) { p++; break; } + } + } + + append(base); + return *this; +} + +template lstring& lstring::split(const char *key, const char *src) { return usplit(key, src); } +template lstring& lstring::isplit(const char *key, const char *src) { return usplit(key, src); } +template lstring& lstring::qsplit(const char *key, const char *src) { return usplit(key, src); } +template lstring& lstring::iqsplit(const char *key, const char *src) { return usplit(key, src); } + +}; + +#endif diff --git a/nall/string/strl.hpp b/nall/string/strl.hpp new file mode 100755 index 00000000..44f6d6f7 --- /dev/null +++ b/nall/string/strl.hpp @@ -0,0 +1,51 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +//strlcpy, strlcat based on OpenBSD implementation by Todd C. Miller + +//return = strlen(src) +unsigned strlcpy(char *dest, const char *src, unsigned length) { + char *d = dest; + const char *s = src; + unsigned n = length; + + if(n) { + while(--n && (*d++ = *s++)); //copy as many bytes as possible, or until null terminator reached + } + + if(!n) { + if(length) *d = 0; + while(*s++); //traverse rest of s, so that s - src == strlen(src) + } + + return (s - src - 1); //return length of copied string, sans null terminator +} + +//return = strlen(src) + min(length, strlen(dest)) +unsigned strlcat(char *dest, const char *src, unsigned length) { + char *d = dest; + const char *s = src; + unsigned n = length; + + while(n-- && *d) d++; //find end of dest + unsigned dlength = d - dest; + n = length - dlength; //subtract length of dest from maximum string length + + if(!n) return dlength + strlen(s); + + while(*s) { + if(n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = 0; + + return dlength + (s - src); //return length of resulting string, sans null terminator +} + +} + +#endif diff --git a/nall/string/strpos.hpp b/nall/string/strpos.hpp new file mode 100755 index 00000000..fe563a6c --- /dev/null +++ b/nall/string/strpos.hpp @@ -0,0 +1,33 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +//usage example: +//if(auto position = strpos(str, key)) print(position(), "\n"); +//prints position of key within str; but only if it is found + +namespace nall { + +template +optional ustrpos(const char *str, const char *key) { + const char *base = str; + + while(*str) { + if(quoteskip(str)) continue; + for(unsigned n = 0;; n++) { + if(key[n] == 0) return { true, (unsigned)(str - base) }; + if(str[n] == 0) return { false, 0 }; + if(!chrequal(str[n], key[n])) break; + } + str++; + } + + return { false, 0 }; +} + +optional strpos(const char *str, const char *key) { return ustrpos(str, key); } +optional istrpos(const char *str, const char *key) { return ustrpos(str, key); } +optional qstrpos(const char *str, const char *key) { return ustrpos(str, key); } +optional iqstrpos(const char *str, const char *key) { return ustrpos(str, key); } + +} + +#endif diff --git a/nall/string/trim.hpp b/nall/string/trim.hpp new file mode 100755 index 00000000..ba049d71 --- /dev/null +++ b/nall/string/trim.hpp @@ -0,0 +1,38 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +//limit defaults to zero, which will underflow on first compare; equivalent to no limit +template char* ltrim(char *str, const char *key) { + unsigned limit = Limit; + if(!key || !*key) return str; + while(strbegin(str, key)) { + char *dest = str, *src = str + strlen(key); + while(true) { + *dest = *src++; + if(!*dest) break; + dest++; + } + if(--limit == 0) break; + } + return str; +} + +template char* rtrim(char *str, const char *key) { + unsigned limit = Limit; + if(!key || !*key) return str; + while(strend(str, key)) { + str[strlen(str) - strlen(key)] = 0; + if(--limit == 0) break; + } + return str; +} + +template char* trim(char *str, const char *key, const char *rkey) { + if(rkey) return ltrim(rtrim(str, rkey), key); + return ltrim(rtrim(str, key), key); +} + +} + +#endif diff --git a/nall/string/utility.hpp b/nall/string/utility.hpp new file mode 100755 index 00000000..e5aa0d11 --- /dev/null +++ b/nall/string/utility.hpp @@ -0,0 +1,286 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +template +bool chrequal(char x, char y) { + if(Insensitive) return chrlower(x) == chrlower(y); + return x == y; +} + +template +bool quoteskip(T *&p) { + if(Quoted == false) return false; + if(*p != '\'' && *p != '\"') return false; + + while(*p == '\'' || *p == '\"') { + char x = *p++; + while(*p && *p++ != x); + } + return true; +} + +template +bool quotecopy(char *&t, T *&p) { + if(Quoted == false) return false; + if(*p != '\'' && *p != '\"') return false; + + while(*p == '\'' || *p == '\"') { + char x = *p++; + *t++ = x; + while(*p && *p != x) *t++ = *p++; + *t++ = *p++; + } + return true; +} + +unsigned strlcpy(string &dest, const char *src, unsigned length) { + dest.reserve(length); + return strlcpy(dest(), src, length); +} + +unsigned strlcat(string &dest, const char *src, unsigned length) { + dest.reserve(length); + return strlcat(dest(), src, length); +} + +string substr(const char *src, unsigned start, unsigned length) { + string dest; + if(length == ~0u) { + //copy entire string + dest = src + start; + } else { + //copy partial string + strlcpy(dest, src + start, length + 1); + } + return dest; +} + +string sha256(const uint8_t *data, unsigned size) { + sha256_ctx sha; + uint8_t hash[32]; + sha256_init(&sha); + sha256_chunk(&sha, data, size); + sha256_final(&sha); + sha256_hash(&sha, hash); + string result; + for(auto &byte : hash) result.append(hex<2>(byte)); + return result; +} + +/* cast.hpp arithmetic -> string */ + +char* integer(char *result, intmax_t value) { + bool negative = value < 0; + if(negative) value = -value; + + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + buffer[size++] = negative ? '-' : '+'; + + for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y]; + result[size] = 0; + return result; +} + +char* decimal(char *result, uintmax_t value) { + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + + for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y]; + result[size] = 0; + return result; +} + +/* general-purpose arithmetic -> string */ + +template string integer(intmax_t value) { + bool negative = value < 0; + if(negative) value = -value; + + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + buffer[size++] = negative ? '-' : '+'; + buffer[size] = 0; + + unsigned length = (length_ == 0 ? size : length_); + char result[length + 1]; + memset(result, padding, length); + result[length] = 0; + + for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) { + result[x] = buffer[y]; + } + + return (const char*)result; +} + +template string linteger(intmax_t value) { + bool negative = value < 0; + if(negative) value = -value; + + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + buffer[size++] = negative ? '-' : '+'; + buffer[size] = 0; + + unsigned length = (length_ == 0 ? size : length_); + char result[length + 1]; + memset(result, padding, length); + result[length] = 0; + + for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) { + result[x] = buffer[y]; + } + + return (const char*)result; +} + +template string decimal(uintmax_t value) { + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + buffer[size] = 0; + + unsigned length = (length_ == 0 ? size : length_); + char result[length + 1]; + memset(result, padding, length); + result[length] = 0; + + for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) { + result[x] = buffer[y]; + } + + return (const char*)result; +} + +template string ldecimal(uintmax_t value) { + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + buffer[size] = 0; + + unsigned length = (length_ == 0 ? size : length_); + char result[length + 1]; + memset(result, padding, length); + result[length] = 0; + + for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) { + result[x] = buffer[y]; + } + + return (const char*)result; +} + +template string hex(uintmax_t value) { + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value & 15; + buffer[size++] = n < 10 ? '0' + n : 'a' + n - 10; + value >>= 4; + } while(value); + + unsigned length = (length_ == 0 ? size : length_); + char result[length + 1]; + memset(result, padding, length); + result[length] = 0; + + for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) { + result[x] = buffer[y]; + } + + return (const char*)result; +} + +template string binary(uintmax_t value) { + char buffer[256]; + unsigned size = 0; + + do { + unsigned n = value & 1; + buffer[size++] = '0' + n; + value >>= 1; + } while(value); + + unsigned length = (length_ == 0 ? size : length_); + char result[length + 1]; + memset(result, padding, length); + result[length] = 0; + + for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) { + result[x] = buffer[y]; + } + + return (const char*)result; +} + +//using sprintf is certainly not the most ideal method to convert +//a double to a string ... but attempting to parse a double by +//hand, digit-by-digit, results in subtle rounding errors. +unsigned fp(char *str, double value) { + char buffer[256]; + sprintf(buffer, "%f", value); + + //remove excess 0's in fraction (2.500000 -> 2.5) + for(char *p = buffer; *p; p++) { + if(*p == '.') { + char *p = buffer + strlen(buffer) - 1; + while(*p == '0') { + if(*(p - 1) != '.') *p = 0; //... but not for eg 1.0 -> 1. + p--; + } + break; + } + } + + unsigned length = strlen(buffer); + if(str) strcpy(str, buffer); + return length + 1; +} + +string fp(double value) { + string temp; + temp.reserve(fp(0, value)); + fp(temp(), value); + return temp; +} + +} + +#endif diff --git a/nall/string/variadic.hpp b/nall/string/variadic.hpp new file mode 100755 index 00000000..c43bfe86 --- /dev/null +++ b/nall/string/variadic.hpp @@ -0,0 +1,11 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +template inline void print(Args&&... args) { + printf("%s", (const char*)string(std::forward(args)...)); +} + +} + +#endif diff --git a/nall/string/wrapper.hpp b/nall/string/wrapper.hpp new file mode 100755 index 00000000..c02d5396 --- /dev/null +++ b/nall/string/wrapper.hpp @@ -0,0 +1,41 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +unsigned string::length() const { return strlen(data); } + +template lstring string::split(const char *key) const { lstring result; result.split(key, data); return result; } +template lstring string::isplit(const char *key) const { lstring result; result.isplit(key, data); return result; } +template lstring string::qsplit(const char *key) const { lstring result; result.qsplit(key, data); return result; } +template lstring string::iqsplit(const char *key) const { lstring result; result.iqsplit(key, data); return result; } + +bool string::equals(const char *str) const { return !strcmp(data, str); } +bool string::iequals(const char *str) const { return !istrcmp(data, str); } + +bool string::wildcard(const char *str) const { return nall::wildcard(data, str); } +bool string::iwildcard(const char *str) const { return nall::iwildcard(data, str); } + +bool string::beginswith(const char *str) const { return strbegin(data, str); } +bool string::ibeginswith(const char *str) const { return istrbegin(data, str); } + +bool string::endswith(const char *str) const { return strend(data, str); } +bool string::iendswith(const char *str) const { return istrend(data, str); } + +string& string::lower() { nall::strlower(data); return *this; } +string& string::upper() { nall::strupper(data); return *this; } +string& string::qlower() { nall::qstrlower(data); return *this; } +string& string::qupper() { nall::qstrupper(data); return *this; } +string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; } + +template string& string::ltrim(const char *key) { nall::ltrim(data, key); return *this; } +template string& string::rtrim(const char *key) { nall::rtrim(data, key); return *this; } +template string& string::trim(const char *key, const char *rkey) { nall::trim (data, key, rkey); return *this; } + +optional string::position(const char *key) const { return strpos(data, key); } +optional string::iposition(const char *key) const { return istrpos(data, key); } +optional string::qposition(const char *key) const { return qstrpos(data, key); } +optional string::iqposition(const char *key) const { return iqstrpos(data, key); } + +} + +#endif diff --git a/nall/string/xml.hpp b/nall/string/xml.hpp new file mode 100755 index 00000000..069639b0 --- /dev/null +++ b/nall/string/xml.hpp @@ -0,0 +1,265 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +//XML v1.0 subset parser +//revision 0.05 + +namespace nall { + +struct xml_attribute { + string name; + string content; + virtual string parse() const; +}; + +struct xml_element : xml_attribute { + string parse() const; + linear_vector attribute; + linear_vector element; + +protected: + void parse_doctype(const char *&data); + bool parse_head(string data); + bool parse_body(const char *&data); + friend xml_element xml_parse(const char *data); +}; + +inline string xml_attribute::parse() const { + string data; + unsigned offset = 0; + + const char *source = content; + while(*source) { + if(*source == '&') { + if(strbegin(source, "<")) { data[offset++] = '<'; source += 4; continue; } + if(strbegin(source, ">")) { data[offset++] = '>'; source += 4; continue; } + if(strbegin(source, "&")) { data[offset++] = '&'; source += 5; continue; } + if(strbegin(source, "'")) { data[offset++] = '\''; source += 6; continue; } + if(strbegin(source, """)) { data[offset++] = '"'; source += 6; continue; } + } + + //reject illegal characters + if(*source == '&') return ""; + if(*source == '<') return ""; + if(*source == '>') return ""; + + data[offset++] = *source++; + } + + data[offset] = 0; + return data; +} + +inline string xml_element::parse() const { + string data; + unsigned offset = 0; + + const char *source = content; + while(*source) { + if(*source == '&') { + if(strbegin(source, "<")) { data[offset++] = '<'; source += 4; continue; } + if(strbegin(source, ">")) { data[offset++] = '>'; source += 4; continue; } + if(strbegin(source, "&")) { data[offset++] = '&'; source += 5; continue; } + if(strbegin(source, "'")) { data[offset++] = '\''; source += 6; continue; } + if(strbegin(source, """)) { data[offset++] = '"'; source += 6; continue; } + } + + if(strbegin(source, "")) { + source += pos() + 3; + continue; + } else { + return ""; + } + } + + if(strbegin(source, "")) { + if(pos() - 9 > 0) { + string cdata = substr(source, 9, pos() - 9); + data.append(cdata); + offset += strlen(cdata); + } + source += 9 + offset + 3; + continue; + } else { + return ""; + } + } + + //reject illegal characters + if(*source == '&') return ""; + if(*source == '<') return ""; + if(*source == '>') return ""; + + data[offset++] = *source++; + } + + data[offset] = 0; + return data; +} + +inline void xml_element::parse_doctype(const char *&data) { + name = "!DOCTYPE"; + const char *content_begin = data; + + signed counter = 0; + while(*data) { + char value = *data++; + if(value == '<') counter++; + if(value == '>') counter--; + if(counter < 0) { + content = substr(content_begin, 0, data - content_begin - 1); + return; + } + } + throw "..."; +} + +inline bool xml_element::parse_head(string data) { + data.qreplace("\t", " "); + data.qreplace("\r", " "); + data.qreplace("\n", " "); + while(qstrpos(data, " ")) data.qreplace(" ", " "); + data.qreplace(" =", "="); + data.qreplace("= ", "="); + data.rtrim(); + + lstring part; + part.qsplit(" ", data); + + name = part[0]; + if(name == "") throw "..."; + + for(unsigned i = 1; i < part.size(); i++) { + lstring side; + side.qsplit("=", part[i]); + if(side.size() != 2) throw "..."; + + xml_attribute attr; + attr.name = side[0]; + attr.content = side[1]; + if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim<1>("\""); + else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim<1>("'"); + else throw "..."; + attribute.append(attr); + } +} + +inline bool xml_element::parse_body(const char *&data) { + while(true) { + if(!*data) return false; + if(*data++ != '<') continue; + if(*data == '/') return false; + + if(strbegin(data, "!DOCTYPE") == true) { + parse_doctype(data); + return true; + } + + if(strbegin(data, "!--")) { + if(auto offset = strpos(data, "-->")) { + data += offset() + 3; + continue; + } else { + throw "..."; + } + } + + if(strbegin(data, "![CDATA[")) { + if(auto offset = strpos(data, "]]>")) { + data += offset() + 3; + continue; + } else { + throw "..."; + } + } + + auto offset = strpos(data, ">"); + if(!offset) throw "..."; + + string tag = substr(data, 0, offset()); + data += offset() + 1; + const char *content_begin = data; + + bool self_terminating = false; + + if(strend(tag, "?") == true) { + self_terminating = true; + tag.rtrim<1>("?"); + } else if(strend(tag, "/") == true) { + self_terminating = true; + tag.rtrim<1>("/"); + } + + parse_head(tag); + if(self_terminating) return true; + + while(*data) { + unsigned index = element.size(); + xml_element node; + if(node.parse_body(data) == false) { + if(*data == '/') { + signed length = data - content_begin - 1; + if(length > 0) content = substr(content_begin, 0, length); + + data++; + auto offset = strpos(data, ">"); + if(!offset) throw "..."; + + tag = substr(data, 0, offset()); + data += offset() + 1; + + tag.replace("\t", " "); + tag.replace("\r", " "); + tag.replace("\n", " "); + while(strpos(tag, " ")) tag.replace(" ", " "); + tag.rtrim(); + + if(name != tag) throw "..."; + return true; + } + } else { + element.append(node); + } + } + } +} + +//ensure there is only one root element +inline bool xml_validate(xml_element &document) { + unsigned root_counter = 0; + + for(unsigned i = 0; i < document.element.size(); i++) { + string &name = document.element[i].name; + if(strbegin(name, "?")) continue; + if(strbegin(name, "!")) continue; + if(++root_counter > 1) return false; + } + + return true; +} + +inline xml_element xml_parse(const char *data) { + xml_element self; + + try { + while(*data) { + xml_element node; + if(node.parse_body(data) == false) { + break; + } else { + self.element.append(node); + } + } + + if(xml_validate(self) == false) throw "..."; + return self; + } catch(const char*) { + xml_element empty; + return empty; + } +} + +} + +#endif diff --git a/nall/ups.hpp b/nall/ups.hpp new file mode 100755 index 00000000..ffcdb2d7 --- /dev/null +++ b/nall/ups.hpp @@ -0,0 +1,223 @@ +#ifndef NALL_UPS_HPP +#define NALL_UPS_HPP + +#include +#include +#include +#include + +namespace nall { + +struct ups { + enum class result : unsigned { + unknown, + success, + patch_unwritable, + patch_invalid, + source_invalid, + target_invalid, + target_too_small, + patch_checksum_invalid, + source_checksum_invalid, + target_checksum_invalid, + }; + + function progress; + + result create( + const uint8_t *sourcedata, unsigned sourcelength, + const uint8_t *targetdata, unsigned targetlength, + const char *patchfilename + ) { + source_data = (uint8_t*)sourcedata, target_data = (uint8_t*)targetdata; + source_length = sourcelength, target_length = targetlength; + source_offset = target_offset = 0; + source_checksum = target_checksum = patch_checksum = ~0; + + if(patch_file.open(patchfilename, file::mode::write) == false) return result::patch_unwritable; + + patch_write('U'); + patch_write('P'); + patch_write('S'); + patch_write('1'); + encode(source_length); + encode(target_length); + + unsigned output_length = source_length > target_length ? source_length : target_length; + unsigned relative = 0; + for(unsigned offset = 0; offset < output_length;) { + uint8_t x = source_read(); + uint8_t y = target_read(); + + if(x == y) { + offset++; + continue; + } + + encode(offset++ - relative); + patch_write(x ^ y); + + while(true) { + if(offset >= output_length) { + patch_write(0x00); + break; + } + + x = source_read(); + y = target_read(); + offset++; + patch_write(x ^ y); + if(x == y) break; + } + + relative = offset; + } + + source_checksum = ~source_checksum; + target_checksum = ~target_checksum; + for(unsigned i = 0; i < 4; i++) patch_write(source_checksum >> (i * 8)); + for(unsigned i = 0; i < 4; i++) patch_write(target_checksum >> (i * 8)); + uint32_t patch_result_checksum = ~patch_checksum; + for(unsigned i = 0; i < 4; i++) patch_write(patch_result_checksum >> (i * 8)); + + patch_file.close(); + return result::success; + } + + result apply( + const uint8_t *patchdata, unsigned patchlength, + const uint8_t *sourcedata, unsigned sourcelength, + uint8_t *targetdata, unsigned &targetlength + ) { + patch_data = (uint8_t*)patchdata, source_data = (uint8_t*)sourcedata, target_data = targetdata; + patch_length = patchlength, source_length = sourcelength, target_length = targetlength; + patch_offset = source_offset = target_offset = 0; + patch_checksum = source_checksum = target_checksum = ~0; + + if(patch_length < 18) return result::patch_invalid; + if(patch_read() != 'U') return result::patch_invalid; + if(patch_read() != 'P') return result::patch_invalid; + if(patch_read() != 'S') return result::patch_invalid; + if(patch_read() != '1') return result::patch_invalid; + + unsigned source_read_length = decode(); + unsigned target_read_length = decode(); + + if(source_length != source_read_length && source_length != target_read_length) return result::source_invalid; + targetlength = (source_length == source_read_length ? target_read_length : source_read_length); + if(target_length < targetlength) return result::target_too_small; + target_length = targetlength; + + while(patch_offset < patch_length - 12) { + unsigned length = decode(); + while(length--) target_write(source_read()); + while(true) { + uint8_t patch_xor = patch_read(); + target_write(patch_xor ^ source_read()); + if(patch_xor == 0) break; + } + } + while(source_offset < source_length) target_write(source_read()); + while(target_offset < target_length) target_write(source_read()); + + uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0; + for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8); + for(unsigned i = 0; i < 4; i++) target_read_checksum |= patch_read() << (i * 8); + uint32_t patch_result_checksum = ~patch_checksum; + source_checksum = ~source_checksum; + target_checksum = ~target_checksum; + for(unsigned i = 0; i < 4; i++) patch_read_checksum |= patch_read() << (i * 8); + + if(patch_result_checksum != patch_read_checksum) return result::patch_invalid; + if(source_checksum == source_read_checksum && source_length == source_read_length) { + if(target_checksum == target_read_checksum && target_length == target_read_length) return result::success; + return result::target_invalid; + } else if(source_checksum == target_read_checksum && source_length == target_read_length) { + if(target_checksum == source_read_checksum && target_length == source_read_length) return result::success; + return result::target_invalid; + } else { + return result::source_invalid; + } + } + +private: + uint8_t *patch_data, *source_data, *target_data; + unsigned patch_length, source_length, target_length; + unsigned patch_offset, source_offset, target_offset; + unsigned patch_checksum, source_checksum, target_checksum; + file patch_file; + + uint8_t patch_read() { + if(patch_offset < patch_length) { + uint8_t n = patch_data[patch_offset++]; + patch_checksum = crc32_adjust(patch_checksum, n); + return n; + } + return 0x00; + } + + uint8_t source_read() { + if(source_offset < source_length) { + uint8_t n = source_data[source_offset++]; + source_checksum = crc32_adjust(source_checksum, n); + return n; + } + return 0x00; + } + + uint8_t target_read() { + uint8_t result = 0x00; + if(target_offset < target_length) { + result = target_data[target_offset]; + target_checksum = crc32_adjust(target_checksum, result); + } + if(((target_offset++ & 255) == 0) && progress) { + progress(target_offset, source_length > target_length ? source_length : target_length); + } + return result; + } + + void patch_write(uint8_t n) { + patch_file.write(n); + patch_checksum = crc32_adjust(patch_checksum, n); + } + + void target_write(uint8_t n) { + if(target_offset < target_length) { + target_data[target_offset] = n; + target_checksum = crc32_adjust(target_checksum, n); + } + if(((target_offset++ & 255) == 0) && progress) { + progress(target_offset, source_length > target_length ? source_length : target_length); + } + } + + void encode(uint64_t offset) { + while(true) { + uint64_t x = offset & 0x7f; + offset >>= 7; + if(offset == 0) { + patch_write(0x80 | x); + break; + } + patch_write(x); + offset--; + } + } + + uint64_t decode() { + uint64_t offset = 0, shift = 1; + while(true) { + uint8_t x = patch_read(); + offset += (x & 0x7f) * shift; + if(x & 0x80) break; + shift <<= 7; + offset += shift; + } + return offset; + } +}; + +} + +#endif diff --git a/nall/utility.hpp b/nall/utility.hpp new file mode 100755 index 00000000..ff8d8bee --- /dev/null +++ b/nall/utility.hpp @@ -0,0 +1,42 @@ +#ifndef NALL_UTILITY_HPP +#define NALL_UTILITY_HPP + +#include +#include + +namespace nall { + template struct enable_if { typedef T type; }; + template struct enable_if {}; + template struct mp_enable_if : enable_if {}; + + template inline void swap(T &x, T &y) { + T temp(std::move(x)); + x = std::move(y); + y = std::move(temp); + } + + template struct base_from_member { + T value; + base_from_member(T value_) : value(value_) {} + }; + + template class optional { + public: + bool valid; + T value; + public: + inline operator bool() const { return valid; } + inline const T& operator()() const { if(!valid) throw; return value; } + inline optional& operator=(const optional &source) { valid = source.valid; value = source.value; return *this; } + inline optional() : valid(false) {} + inline optional(bool valid, const T &value) : valid(valid), value(value) {} + }; + + template inline T* allocate(unsigned size, const T &value) { + T *array = new T[size]; + for(unsigned i = 0; i < size; i++) array[i] = value; + return array; + } +} + +#endif diff --git a/nall/varint.hpp b/nall/varint.hpp new file mode 100755 index 00000000..d91ea2a5 --- /dev/null +++ b/nall/varint.hpp @@ -0,0 +1,121 @@ +#ifndef NALL_VARINT_HPP +#define NALL_VARINT_HPP + +#include +#include +#include + +namespace nall { + template class uint_t { + private: + unsigned data; + + public: + inline operator unsigned() const { return data; } + inline unsigned operator ++(int) { unsigned r = data; data = uclip(data + 1); return r; } + inline unsigned operator --(int) { unsigned r = data; data = uclip(data - 1); return r; } + inline unsigned operator ++() { return data = uclip(data + 1); } + inline unsigned operator --() { return data = uclip(data - 1); } + inline unsigned operator =(const unsigned i) { return data = uclip(i); } + inline unsigned operator |=(const unsigned i) { return data = uclip(data | i); } + inline unsigned operator ^=(const unsigned i) { return data = uclip(data ^ i); } + inline unsigned operator &=(const unsigned i) { return data = uclip(data & i); } + inline unsigned operator<<=(const unsigned i) { return data = uclip(data << i); } + inline unsigned operator>>=(const unsigned i) { return data = uclip(data >> i); } + inline unsigned operator +=(const unsigned i) { return data = uclip(data + i); } + inline unsigned operator -=(const unsigned i) { return data = uclip(data - i); } + inline unsigned operator *=(const unsigned i) { return data = uclip(data * i); } + inline unsigned operator /=(const unsigned i) { return data = uclip(data / i); } + inline unsigned operator %=(const unsigned i) { return data = uclip(data % i); } + + inline uint_t() : data(0) {} + inline uint_t(const unsigned i) : data(uclip(i)) {} + + template inline unsigned operator=(const uint_t &i) { return data = uclip((unsigned)i); } + template inline uint_t(const uint_t &i) : data(uclip(i)) {} + }; + + template class int_t { + private: + signed data; + + public: + inline operator signed() const { return data; } + inline signed operator ++(int) { signed r = data; data = sclip(data + 1); return r; } + inline signed operator --(int) { signed r = data; data = sclip(data - 1); return r; } + inline signed operator ++() { return data = sclip(data + 1); } + inline signed operator --() { return data = sclip(data - 1); } + inline signed operator =(const signed i) { return data = sclip(i); } + inline signed operator |=(const signed i) { return data = sclip(data | i); } + inline signed operator ^=(const signed i) { return data = sclip(data ^ i); } + inline signed operator &=(const signed i) { return data = sclip(data & i); } + inline signed operator<<=(const signed i) { return data = sclip(data << i); } + inline signed operator>>=(const signed i) { return data = sclip(data >> i); } + inline signed operator +=(const signed i) { return data = sclip(data + i); } + inline signed operator -=(const signed i) { return data = sclip(data - i); } + inline signed operator *=(const signed i) { return data = sclip(data * i); } + inline signed operator /=(const signed i) { return data = sclip(data / i); } + inline signed operator %=(const signed i) { return data = sclip(data % i); } + + inline int_t() : data(0) {} + inline int_t(const signed i) : data(sclip(i)) {} + }; + + class varuint_t { + private: + unsigned data; + unsigned mask; + + public: + inline operator unsigned() const { return data; } + inline unsigned operator ++(int) { unsigned r = data; data = (data + 1) & mask; return r; } + inline unsigned operator --(int) { unsigned r = data; data = (data - 1) & mask; return r; } + inline unsigned operator ++() { return data = (data + 1) & mask; } + inline unsigned operator --() { return data = (data - 1) & mask; } + inline unsigned operator =(const unsigned i) { return data = (i) & mask; } + inline unsigned operator |=(const unsigned i) { return data = (data | i) & mask; } + inline unsigned operator ^=(const unsigned i) { return data = (data ^ i) & mask; } + inline unsigned operator &=(const unsigned i) { return data = (data & i) & mask; } + inline unsigned operator<<=(const unsigned i) { return data = (data << i) & mask; } + inline unsigned operator>>=(const unsigned i) { return data = (data >> i) & mask; } + inline unsigned operator +=(const unsigned i) { return data = (data + i) & mask; } + inline unsigned operator -=(const unsigned i) { return data = (data - i) & mask; } + inline unsigned operator *=(const unsigned i) { return data = (data * i) & mask; } + inline unsigned operator /=(const unsigned i) { return data = (data / i) & mask; } + inline unsigned operator %=(const unsigned i) { return data = (data % i) & mask; } + + inline void bits(unsigned bits) { mask = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1); data &= mask; } + inline varuint_t() : data(0), mask(~0U) {} + inline varuint_t(const unsigned i) : data(i), mask(~0U) {} + }; + + class varuintmax_t { + private: + uintmax_t data; + uintmax_t mask; + + public: + inline operator uintmax_t() const { return data; } + inline uintmax_t operator ++(int) { uintmax_t r = data; data = (data + 1) & mask; return r; } + inline uintmax_t operator --(int) { uintmax_t r = data; data = (data - 1) & mask; return r; } + inline uintmax_t operator ++() { return data = (data + 1) & mask; } + inline uintmax_t operator --() { return data = (data - 1) & mask; } + inline uintmax_t operator =(const uintmax_t i) { return data = (i) & mask; } + inline uintmax_t operator |=(const uintmax_t i) { return data = (data | i) & mask; } + inline uintmax_t operator ^=(const uintmax_t i) { return data = (data ^ i) & mask; } + inline uintmax_t operator &=(const uintmax_t i) { return data = (data & i) & mask; } + inline uintmax_t operator<<=(const uintmax_t i) { return data = (data << i) & mask; } + inline uintmax_t operator>>=(const uintmax_t i) { return data = (data >> i) & mask; } + inline uintmax_t operator +=(const uintmax_t i) { return data = (data + i) & mask; } + inline uintmax_t operator -=(const uintmax_t i) { return data = (data - i) & mask; } + inline uintmax_t operator *=(const uintmax_t i) { return data = (data * i) & mask; } + inline uintmax_t operator /=(const uintmax_t i) { return data = (data / i) & mask; } + inline uintmax_t operator %=(const uintmax_t i) { return data = (data % i) & mask; } + + inline void bits(unsigned bits) { mask = (1ULL << (bits - 1)) + ((1ULL << (bits - 1)) - 1); data &= mask; } + inline varuintmax_t() : data(0), mask(~0ULL) {} + inline varuintmax_t(const uintmax_t i) : data(i), mask(~0ULL) {} + }; +} + +#endif diff --git a/nall/vector.hpp b/nall/vector.hpp new file mode 100755 index 00000000..7c605855 --- /dev/null +++ b/nall/vector.hpp @@ -0,0 +1,409 @@ +#ifndef NALL_VECTOR_HPP +#define NALL_VECTOR_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nall { + template struct vector { + struct exception_out_of_bounds{}; + + protected: + T *pool; + unsigned poolsize; + unsigned objectsize; + + public: + unsigned size() const { return objectsize; } + unsigned capacity() const { return poolsize; } + + void reset() { + if(pool) { + for(unsigned n = 0; n < objectsize; n++) pool[n].~T(); + free(pool); + } + pool = nullptr; + poolsize = 0; + objectsize = 0; + } + + void reserve(unsigned size) { + size = bit::round(size); //amortize growth + T *copy = (T*)calloc(size, sizeof(T)); + for(unsigned n = 0; n < min(size, objectsize); n++) new(copy + n) T(pool[n]); + for(unsigned n = 0; n < objectsize; n++) pool[n].~T(); + free(pool); + pool = copy; + poolsize = size; + objectsize = min(size, objectsize); + } + + template + void append(const T& data, Args&&... args) { + append(data); + append(std::forward(args)...); + } + + void append(const T& data) { + if(objectsize + 1 > poolsize) reserve(objectsize + 1); + new(pool + objectsize++) T(data); + } + + void remove(unsigned index, unsigned count = 1) { + for(unsigned n = index; count + n < objectsize; n++) { + pool[n] = pool[count + n]; + } + objectsize = (count + index >= objectsize) ? index : objectsize - count; + } + + //access + inline T& operator[](unsigned position) { + if(position >= objectsize) throw exception_out_of_bounds(); + return pool[position]; + } + + inline const T& operator[](unsigned position) const { + if(position >= objectsize) throw exception_out_of_bounds(); + return pool[position]; + } + + inline const T& operator()(unsigned position, const T& data) const { + if(position >= objectsize) return data; + return pool[position]; + } + + //iteration + T* begin() { return &pool[0]; } + T* end() { return &pool[objectsize]; } + const T* begin() const { return &pool[0]; } + const T* end() const { return &pool[objectsize]; } + + //copy + inline vector& operator=(const vector &source) { + reset(); + reserve(source.capacity()); + for(auto &data : source) append(data); + return *this; + } + + vector(const vector &source) : pool(nullptr), poolsize(0), objectsize(0) { + operator=(source); + } + + //move + inline vector& operator=(vector &&source) { + reset(); + pool = source.pool, poolsize = source.poolsize, objectsize = source.objectsize; + source.pool = nullptr, source.poolsize = 0, source.objectsize = 0; + return *this; + } + + vector(vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { + operator=(std::move(source)); + } + + //construction + vector() : pool(nullptr), poolsize(0), objectsize(0) { + } + + vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { + for(auto &data : list) append(data); + } + + ~vector() { + reset(); + } + }; + + //linear_vector + //memory: O(capacity * 2) + // + //linear_vector uses placement new + manual destructor calls to create a + //contiguous block of memory for all objects. accessing individual elements + //is fast, though resizing the array incurs significant overhead. + //reserve() overhead is reduced from quadratic time to amortized constant time + //by resizing twice as much as requested. + // + //if objects hold memory address references to themselves (introspection), a + //valid copy constructor will be needed to keep pointers valid. + + template struct linear_vector { + protected: + T *pool; + unsigned poolsize, objectsize; + + public: + unsigned size() const { return objectsize; } + unsigned capacity() const { return poolsize; } + + void reset() { + if(pool) { + for(unsigned i = 0; i < objectsize; i++) pool[i].~T(); + free(pool); + } + pool = nullptr; + poolsize = 0; + objectsize = 0; + } + + void reserve(unsigned newsize) { + newsize = bit::round(newsize); //round to nearest power of two (for amortized growth) + + T *poolcopy = (T*)calloc(newsize, sizeof(T)); + for(unsigned i = 0; i < min(objectsize, newsize); i++) new(poolcopy + i) T(pool[i]); + for(unsigned i = 0; i < objectsize; i++) pool[i].~T(); + free(pool); + pool = poolcopy; + poolsize = newsize; + objectsize = min(objectsize, newsize); + } + + void resize(unsigned newsize) { + if(newsize > poolsize) reserve(newsize); + + if(newsize < objectsize) { + //vector is shrinking; destroy excess objects + for(unsigned i = newsize; i < objectsize; i++) pool[i].~T(); + } else if(newsize > objectsize) { + //vector is expanding; allocate new objects + for(unsigned i = objectsize; i < newsize; i++) new(pool + i) T; + } + + objectsize = newsize; + } + + void append(const T data) { + if(objectsize + 1 > poolsize) reserve(objectsize + 1); + new(pool + objectsize++) T(data); + } + + template void insert(unsigned index, const U list) { + linear_vector merged; + for(unsigned i = 0; i < index; i++) merged.append(pool[i]); + for(auto &item : list) merged.append(item); + for(unsigned i = index; i < objectsize; i++) merged.append(pool[i]); + operator=(merged); + } + + void insert(unsigned index, const T item) { + insert(index, linear_vector{ item }); + } + + void remove(unsigned index, unsigned count = 1) { + for(unsigned i = index; count + i < objectsize; i++) { + pool[i] = pool[count + i]; + } + if(count + index >= objectsize) resize(index); //every element >= index was removed + else resize(objectsize - count); + } + + linear_vector() : pool(nullptr), poolsize(0), objectsize(0) { + } + + linear_vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { + for(const T *p = list.begin(); p != list.end(); ++p) append(*p); + } + + ~linear_vector() { + reset(); + } + + //copy + inline linear_vector& operator=(const linear_vector &source) { + reset(); + reserve(source.capacity()); + resize(source.size()); + for(unsigned i = 0; i < source.size(); i++) operator[](i) = source.operator[](i); + return *this; + } + + linear_vector(const linear_vector &source) : pool(nullptr), poolsize(0), objectsize(0) { + operator=(source); + } + + //move + inline linear_vector& operator=(linear_vector &&source) { + reset(); + pool = source.pool; + poolsize = source.poolsize; + objectsize = source.objectsize; + source.pool = nullptr; + source.reset(); + return *this; + } + + linear_vector(linear_vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { + operator=(std::move(source)); + } + + //index + inline T& operator[](unsigned index) { + if(index >= objectsize) resize(index + 1); + return pool[index]; + } + + inline const T& operator[](unsigned index) const { + if(index >= objectsize) throw "vector[] out of bounds"; + return pool[index]; + } + + //iteration + T* begin() { return &pool[0]; } + T* end() { return &pool[objectsize]; } + const T* begin() const { return &pool[0]; } + const T* end() const { return &pool[objectsize]; } + }; + + //pointer_vector + //memory: O(1) + // + //pointer_vector keeps an array of pointers to each vector object. this adds + //significant overhead to individual accesses, but allows for optimal memory + //utilization. + // + //by guaranteeing that the base memory address of each objects never changes, + //this avoids the need for an object to have a valid copy constructor. + + template struct pointer_vector { + protected: + T **pool; + unsigned poolsize, objectsize; + + public: + unsigned size() const { return objectsize; } + unsigned capacity() const { return poolsize; } + + void reset() { + if(pool) { + for(unsigned i = 0; i < objectsize; i++) { if(pool[i]) delete pool[i]; } + free(pool); + } + pool = nullptr; + poolsize = 0; + objectsize = 0; + } + + void reserve(unsigned newsize) { + newsize = bit::round(newsize); //round to nearest power of two (for amortized growth) + + for(unsigned i = newsize; i < objectsize; i++) { + if(pool[i]) { delete pool[i]; pool[i] = 0; } + } + + pool = (T**)realloc(pool, newsize * sizeof(T*)); + for(unsigned i = poolsize; i < newsize; i++) pool[i] = 0; + poolsize = newsize; + objectsize = min(objectsize, newsize); + } + + void resize(unsigned newsize) { + if(newsize > poolsize) reserve(newsize); + + for(unsigned i = newsize; i < objectsize; i++) { + if(pool[i]) { delete pool[i]; pool[i] = 0; } + } + + objectsize = newsize; + } + + void append(const T data) { + if(objectsize + 1 > poolsize) reserve(objectsize + 1); + pool[objectsize++] = new T(data); + } + + template void insert(unsigned index, const U list) { + pointer_vector merged; + for(unsigned i = 0; i < index; i++) merged.append(*pool[i]); + for(auto &item : list) merged.append(item); + for(unsigned i = index; i < objectsize; i++) merged.append(*pool[i]); + operator=(merged); + } + + void insert(unsigned index, const T item) { + insert(index, pointer_vector{ item }); + } + + void remove(unsigned index, unsigned count = 1) { + for(unsigned i = index; count + i < objectsize; i++) { + *pool[i] = *pool[count + i]; + } + if(count + index >= objectsize) resize(index); //every element >= index was removed + else resize(objectsize - count); + } + + pointer_vector() : pool(nullptr), poolsize(0), objectsize(0) { + } + + pointer_vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { + for(const T *p = list.begin(); p != list.end(); ++p) append(*p); + } + + ~pointer_vector() { + reset(); + } + + //copy + inline pointer_vector& operator=(const pointer_vector &source) { + reset(); + reserve(source.capacity()); + resize(source.size()); + for(unsigned i = 0; i < source.size(); i++) operator[](i) = source.operator[](i); + return *this; + } + + pointer_vector(const pointer_vector &source) : pool(nullptr), poolsize(0), objectsize(0) { + operator=(source); + } + + //move + inline pointer_vector& operator=(pointer_vector &&source) { + reset(); + pool = source.pool; + poolsize = source.poolsize; + objectsize = source.objectsize; + source.pool = nullptr; + source.reset(); + return *this; + } + + pointer_vector(pointer_vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { + operator=(std::move(source)); + } + + //index + inline T& operator[](unsigned index) { + if(index >= objectsize) resize(index + 1); + if(!pool[index]) pool[index] = new T; + return *pool[index]; + } + + inline const T& operator[](unsigned index) const { + if(index >= objectsize || !pool[index]) throw "vector[] out of bounds"; + return *pool[index]; + } + + //iteration + struct iterator { + bool operator!=(const iterator &source) const { return index != source.index; } + T& operator*() { return vector.operator[](index); } + iterator& operator++() { index++; return *this; } + iterator(const pointer_vector &vector, unsigned index) : vector(vector), index(index) {} + private: + const pointer_vector &vector; + unsigned index; + }; + + iterator begin() { return iterator(*this, 0); } + iterator end() { return iterator(*this, objectsize); } + const iterator begin() const { return iterator(*this, 0); } + const iterator end() const { return iterator(*this, objectsize); } + }; +} + +#endif diff --git a/nall/windows/detour.hpp b/nall/windows/detour.hpp new file mode 100755 index 00000000..e270f318 --- /dev/null +++ b/nall/windows/detour.hpp @@ -0,0 +1,192 @@ +#ifndef NALL_WINDOWS_DETOUR_HPP +#define NALL_WINDOWS_DETOUR_HPP + +#include +#include +#include +#include +#include + +namespace nall { + +#define Copy 0 +#define RelNear 1 + +struct detour { + static bool insert(const string &moduleName, const string &functionName, void *&source, void *target); + static bool remove(const string &moduleName, const string &functionName, void *&source); + +protected: + static unsigned length(const uint8_t *function); + static unsigned mirror(uint8_t *target, const uint8_t *source); + + struct opcode { + uint16_t prefix; + unsigned length; + unsigned mode; + uint16_t modify; + }; + static opcode opcodes[]; +}; + +//TODO: +//* fs:, gs: should force another opcode copy +//* conditional branches within +5-byte range should fail +detour::opcode detour::opcodes[] = { + { 0x50, 1 }, //push eax + { 0x51, 1 }, //push ecx + { 0x52, 1 }, //push edx + { 0x53, 1 }, //push ebx + { 0x54, 1 }, //push esp + { 0x55, 1 }, //push ebp + { 0x56, 1 }, //push esi + { 0x57, 1 }, //push edi + { 0x58, 1 }, //pop eax + { 0x59, 1 }, //pop ecx + { 0x5a, 1 }, //pop edx + { 0x5b, 1 }, //pop ebx + { 0x5c, 1 }, //pop esp + { 0x5d, 1 }, //pop ebp + { 0x5e, 1 }, //pop esi + { 0x5f, 1 }, //pop edi + { 0x64, 1 }, //fs: + { 0x65, 1 }, //gs: + { 0x68, 5 }, //push dword + { 0x6a, 2 }, //push byte + { 0x74, 2, RelNear, 0x0f84 }, //je near -> je far + { 0x75, 2, RelNear, 0x0f85 }, //jne near -> jne far + { 0x89, 2 }, //mov reg,reg + { 0x8b, 2 }, //mov reg,reg + { 0x90, 1 }, //nop + { 0xa1, 5 }, //mov eax,[dword] + { 0xeb, 2, RelNear, 0xe9 }, //jmp near -> jmp far +}; + +bool detour::insert(const string &moduleName, const string &functionName, void *&source, void *target) { + HMODULE module = GetModuleHandleW(utf16_t(moduleName)); + if(!module) return false; + + uint8_t *sourceData = (uint8_t*)GetProcAddress(module, functionName); + if(!sourceData) return false; + + unsigned sourceLength = detour::length(sourceData); + if(sourceLength < 5) { + //unable to clone enough bytes to insert hook + #if 1 + string output = { "detour::insert(", moduleName, "::", functionName, ") failed: " }; + for(unsigned n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " "); + output.rtrim<1>(" "); + MessageBoxA(0, output, "nall::detour", MB_OK); + #endif + return false; + } + + uint8_t *mirrorData = new uint8_t[512](); + detour::mirror(mirrorData, sourceData); + + DWORD privileges; + VirtualProtect((void*)mirrorData, 512, PAGE_EXECUTE_READWRITE, &privileges); + VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges); + uintmax_t address = (uintmax_t)target - ((uintmax_t)sourceData + 5); + sourceData[0] = 0xe9; //jmp target + sourceData[1] = address >> 0; + sourceData[2] = address >> 8; + sourceData[3] = address >> 16; + sourceData[4] = address >> 24; + VirtualProtect((void*)sourceData, 256, privileges, &privileges); + + source = (void*)mirrorData; + return true; +} + +bool detour::remove(const string &moduleName, const string &functionName, void *&source) { + HMODULE module = GetModuleHandleW(utf16_t(moduleName)); + if(!module) return false; + + uint8_t *sourceData = (uint8_t*)GetProcAddress(module, functionName); + if(!sourceData) return false; + + uint8_t *mirrorData = (uint8_t*)source; + if(mirrorData == sourceData) return false; //hook was never installed + + unsigned length = detour::length(256 + mirrorData); + if(length < 5) return false; + + DWORD privileges; + VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges); + for(unsigned n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n]; + VirtualProtect((void*)sourceData, 256, privileges, &privileges); + + source = (void*)sourceData; + delete[] mirrorData; + return true; +} + +unsigned detour::length(const uint8_t *function) { + unsigned length = 0; + while(length < 5) { + detour::opcode *opcode = 0; + foreach(op, detour::opcodes) { + if(function[length] == op.prefix) { + opcode = &op; + break; + } + } + if(opcode == 0) break; + length += opcode->length; + } + return length; +} + +unsigned detour::mirror(uint8_t *target, const uint8_t *source) { + const uint8_t *entryPoint = source; + for(unsigned n = 0; n < 256; n++) target[256 + n] = source[n]; + + unsigned size = detour::length(source); + while(size) { + detour::opcode *opcode = 0; + foreach(op, detour::opcodes) { + if(*source == op.prefix) { + opcode = &op; + break; + } + } + + switch(opcode->mode) { + case Copy: + for(unsigned n = 0; n < opcode->length; n++) *target++ = *source++; + break; + case RelNear: { + source++; + uintmax_t sourceAddress = (uintmax_t)source + 1 + (int8_t)*source; + *target++ = opcode->modify; + if(opcode->modify >> 8) *target++ = opcode->modify >> 8; + uintmax_t targetAddress = (uintmax_t)target + 4; + uintmax_t address = sourceAddress - targetAddress; + *target++ = address >> 0; + *target++ = address >> 8; + *target++ = address >> 16; + *target++ = address >> 24; + source += 2; + } break; + } + + size -= opcode->length; + } + + uintmax_t address = (entryPoint + detour::length(entryPoint)) - (target + 5); + *target++ = 0xe9; //jmp entryPoint + *target++ = address >> 0; + *target++ = address >> 8; + *target++ = address >> 16; + *target++ = address >> 24; + + return source - entryPoint; +} + +#undef Implied +#undef RelNear + +} + +#endif diff --git a/nall/windows/launcher.hpp b/nall/windows/launcher.hpp new file mode 100755 index 00000000..914683ec --- /dev/null +++ b/nall/windows/launcher.hpp @@ -0,0 +1,94 @@ +#ifndef NALL_WINDOWS_LAUNCHER_HPP +#define NALL_WINDOWS_LAUNCHER_HPP + +namespace nall { + +//launch a new process and inject specified DLL into it + +bool launch(const char *applicationName, const char *libraryName, uint32_t entryPoint) { + //if a launcher does not send at least one message, a wait cursor will appear + PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0); + MSG msg; + GetMessage(&msg, 0, 0, 0); + + STARTUPINFOW si; + PROCESS_INFORMATION pi; + + memset(&si, 0, sizeof(STARTUPINFOW)); + BOOL result = CreateProcessW( + utf16_t(applicationName), GetCommandLineW(), NULL, NULL, TRUE, + DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, //do not break if application creates its own processes + NULL, NULL, &si, &pi + ); + if(result == false) return false; + + uint8_t entryData[1024], entryHook[1024] = { + 0x68, 0x00, 0x00, 0x00, 0x00, //push libraryName + 0xb8, 0x00, 0x00, 0x00, 0x00, //mov eax,LoadLibraryW + 0xff, 0xd0, //call eax + 0xcd, 0x03, //int 3 + }; + + entryHook[1] = (uint8_t)((entryPoint + 14) >> 0); + entryHook[2] = (uint8_t)((entryPoint + 14) >> 8); + entryHook[3] = (uint8_t)((entryPoint + 14) >> 16); + entryHook[4] = (uint8_t)((entryPoint + 14) >> 24); + + uint32_t pLoadLibraryW = (uint32_t)GetProcAddress(GetModuleHandleW(L"kernel32"), "LoadLibraryW"); + entryHook[6] = pLoadLibraryW >> 0; + entryHook[7] = pLoadLibraryW >> 8; + entryHook[8] = pLoadLibraryW >> 16; + entryHook[9] = pLoadLibraryW >> 24; + + utf16_t buffer = utf16_t(libraryName); + memcpy(entryHook + 14, buffer, 2 * wcslen(buffer) + 2); + + while(true) { + DEBUG_EVENT event; + WaitForDebugEvent(&event, INFINITE); + + if(event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; + + if(event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { + if(event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { + if(event.u.Exception.ExceptionRecord.ExceptionAddress == (void*)(entryPoint + 14 - 1)) { + HANDLE hProcess = OpenProcess(0, FALSE, event.dwProcessId); + HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, event.dwThreadId); + + CONTEXT context; + context.ContextFlags = CONTEXT_FULL; + GetThreadContext(hThread, &context); + + WriteProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryData, sizeof entryData, NULL); + context.Eip = entryPoint; + SetThreadContext(hThread, &context); + + CloseHandle(hThread); + CloseHandle(hProcess); + } + + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + continue; + } + + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); + continue; + } + + if(event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { + ReadProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryData, sizeof entryData, NULL); + WriteProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryHook, sizeof entryHook, NULL); + + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + continue; + } + + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + } + + return true; +} + +} + +#endif diff --git a/nall/windows/utf8.hpp b/nall/windows/utf8.hpp new file mode 100755 index 00000000..f5597b85 --- /dev/null +++ b/nall/windows/utf8.hpp @@ -0,0 +1,86 @@ +#ifndef NALL_UTF8_HPP +#define NALL_UTF8_HPP + +//UTF-8 <> UTF-16 conversion +//used only for Win32; Linux, etc use UTF-8 internally + +#if defined(_WIN32) + +#undef UNICODE +#undef _WIN32_WINNT +#undef NOMINMAX +#define UNICODE +#define _WIN32_WINNT 0x0501 +#define NOMINMAX +#include +#undef interface + +namespace nall { + //UTF-8 to UTF-16 + class utf16_t { + public: + operator wchar_t*() { + return buffer; + } + + operator const wchar_t*() const { + return buffer; + } + + utf16_t(const char *s = "") { + if(!s) s = ""; + unsigned length = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0); + buffer = new wchar_t[length + 1](); + MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length); + } + + ~utf16_t() { + delete[] buffer; + } + + private: + wchar_t *buffer; + }; + + //UTF-16 to UTF-8 + class utf8_t { + public: + operator char*() { + return buffer; + } + + operator const char*() const { + return buffer; + } + + utf8_t(const wchar_t *s = L"") { + if(!s) s = L""; + unsigned length = WideCharToMultiByte(CP_UTF8, 0, s, -1, 0, 0, (const char*)0, (BOOL*)0); + buffer = new char[length + 1](); + WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, (const char*)0, (BOOL*)0); + } + + ~utf8_t() { + delete[] buffer; + } + + utf8_t(const utf8_t&) = delete; + utf8_t& operator=(const utf8_t&) = delete; + + private: + char *buffer; + }; + + inline void utf8_args(int &argc, char **&argv) { + wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc); + argv = new char*[argc]; + for(unsigned i = 0; i < argc; i++) { + argv[i] = new char[_MAX_PATH]; + strcpy(argv[i], nall::utf8_t(wargv[i])); + } + } +} + +#endif //if defined(_WIN32) + +#endif diff --git a/nall/zip.hpp b/nall/zip.hpp new file mode 100755 index 00000000..ad9c7506 --- /dev/null +++ b/nall/zip.hpp @@ -0,0 +1,124 @@ +#ifndef NALL_UNZIP_HPP +#define NALL_UNZIP_HPP + +#include +#include +#include +#include + +namespace nall { + +struct zip { + struct File { + string name; + const uint8_t *data; + unsigned size; + unsigned csize; + unsigned cmode; //0 = uncompressed, 8 = deflate + unsigned crc32; + }; + + inline bool open(const string &filename) { + close(); + if(fm.open(filename, filemap::mode::read) == false) return false; + if(open(fm.data(), fm.size()) == false) { + fm.close(); + return false; + } + return true; + } + + inline bool open(const uint8_t *data, unsigned size) { + if(size < 22) return false; + + filedata = data; + filesize = size; + + file.reset(); + + const uint8_t *footer = data + size - 22; + const uint8_t *directory = data + read(footer + 16, 4); + + while(true) { + unsigned signature = read(directory + 0, 4); + if(signature != 0x02014b50) break; + + File file; + file.cmode = read(directory + 10, 2); + file.crc32 = read(directory + 16, 4); + file.csize = read(directory + 20, 4); + file.size = read(directory + 24, 4); + + unsigned namelength = read(directory + 28, 2); + unsigned extralength = read(directory + 30, 2); + unsigned commentlength = read(directory + 32, 2); + + char *filename = new char[namelength + 1]; + memcpy(filename, directory + 46, namelength); + filename[namelength] = 0; + file.name = filename; + delete[] filename; + + unsigned offset = read(directory + 42, 4); + unsigned offsetNL = read(data + offset + 26, 2); + unsigned offsetEL = read(data + offset + 28, 2); + file.data = data + offset + 30 + offsetNL + offsetEL; + + directory += 46 + namelength + extralength + commentlength; + + this->file.append(file); + } + + return true; + } + + inline bool extract(File &file, uint8_t *&data, unsigned &size) { + data = 0, size = 0; + + if(file.cmode == 0) { + size = file.size; + data = new uint8_t[size]; + memcpy(data, file.data, size); + return true; + } + + if(file.cmode == 8) { + size = file.size; + data = new uint8_t[size]; + if(inflate(data, size, file.data, file.csize) == false) { + delete[] data; + size = 0; + return false; + } + return true; + } + + return false; + } + + inline void close() { + if(fm.open()) fm.close(); + } + + ~zip() { + close(); + } + +protected: + filemap fm; + const uint8_t *filedata; + unsigned filesize; + + unsigned read(const uint8_t *data, unsigned size) { + unsigned result = 0, shift = 0; + while(size--) { result |= *data++ << shift; shift += 8; } + return result; + } + +public: + linear_vector file; +}; + +} + +#endif diff --git a/nes/Makefile b/nes/Makefile new file mode 100755 index 00000000..ef680573 --- /dev/null +++ b/nes/Makefile @@ -0,0 +1,16 @@ +nes_objects := nes-interface nes-system nes-scheduler nes-input +nes_objects += nes-memory nes-cartridge nes-cpu nes-apu nes-ppu +nes_objects += nes-cheat nes-video +objects += $(nes_objects) + +obj/nes-interface.o: $(nes)/interface/interface.cpp $(call rwildcard,$(nes)/interface/) +obj/nes-system.o: $(nes)/system/system.cpp $(call rwildcard,$(nes)/system/) +obj/nes-scheduler.o: $(nes)/scheduler/scheduler.cpp $(call rwildcard,$(nes)/scheduler/) +obj/nes-input.o: $(nes)/input/input.cpp $(call rwildcard,$(nes)/input/) +obj/nes-memory.o: $(nes)/memory/memory.cpp $(call rwildcard,$(nes)/memory/) +obj/nes-cartridge.o: $(nes)/cartridge/cartridge.cpp $(call rwildcard,$(nes)/cartridge/) +obj/nes-cpu.o: $(nes)/cpu/cpu.cpp $(call rwildcard,$(nes)/cpu/) +obj/nes-apu.o: $(nes)/apu/apu.cpp $(call rwildcard,$(nes)/apu/) +obj/nes-ppu.o: $(nes)/ppu/ppu.cpp $(call rwildcard,$(nes)/ppu/) +obj/nes-cheat.o: $(nes)/cheat/cheat.cpp $(call rwildcard,$(nes)/cheat/) +obj/nes-video.o: $(nes)/video/video.cpp $(call rwildcard,$(nes)/video/) diff --git a/nes/apu/apu.cpp b/nes/apu/apu.cpp new file mode 100755 index 00000000..5a41bcd8 --- /dev/null +++ b/nes/apu/apu.cpp @@ -0,0 +1,329 @@ +#include + +namespace NES { + +#include "envelope.cpp" +#include "sweep.cpp" +#include "pulse.cpp" +#include "triangle.cpp" +#include "noise.cpp" +#include "dmc.cpp" +#include "serialization.cpp" +APU apu; + +const uint8 APU::length_counter_table[32] = { + 0x0a, 0xfe, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06, 0xa0, 0x08, 0x3c, 0x0a, 0x0e, 0x0c, 0x1a, 0x0e, + 0x0c, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, 0xc0, 0x18, 0x48, 0x1a, 0x10, 0x1c, 0x20, 0x1e, +}; + +const uint16 APU::ntsc_noise_period_table[16] = { + 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068, +}; + +const uint16 APU::pal_noise_period_table[16] = { + 4, 7, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778, +}; + +const uint16 APU::ntsc_dmc_period_table[16] = { + 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54, +}; + +const uint16 APU::pal_dmc_period_table[16] = { + 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50, +}; + +void APU::Main() { + apu.main(); +} + +void APU::main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + unsigned pulse_output, triangle_output, noise_output, dmc_output; + + pulse_output = pulse[0].clock(); + pulse_output += pulse[1].clock(); + triangle_output = triangle.clock(); + noise_output = noise.clock(); + dmc_output = dmc.clock(); + + clock_frame_counter_divider(); + + signed output = pulse_dac[pulse_output] + dmc_triangle_noise_dac[dmc_output][triangle_output][noise_output]; + + output = filter.run_hipass_strong(output); + output += cartridge_sample; + output = filter.run_hipass_weak(output); + //output = filter.run_lopass(output); + output = sclamp<16>(output); + + interface->audioSample(output); + + tick(); + } +} + +void APU::tick() { + clock += 12; + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); +} + +void APU::set_irq_line() { + cpu.set_irq_apu_line(frame.irq_pending || dmc.irq_pending); +} + +void APU::set_sample(int16 sample) { + cartridge_sample = sample; +} + +void APU::power() { + filter.hipass_strong = 0; + filter.hipass_weak = 0; + filter.lopass = 0; + + pulse[0].power(); + pulse[1].power(); + triangle.power(); + noise.power(); + dmc.power(); +} + +void APU::reset() { + Processor::create(APU::Main, 21477272); + + pulse[0].reset(); + pulse[1].reset(); + triangle.reset(); + noise.reset(); + dmc.reset(); + + frame.irq_pending = 0; + + frame.mode = 0; + frame.counter = 0; + frame.divider = 1; + + enabled_channels = 0; + cartridge_sample = 0; + + set_irq_line(); +} + +uint8 APU::read(uint16 addr) { + if(addr == 0x4015) { + uint8 result = 0x00; + result |= pulse[0].length_counter ? 0x01 : 0; + result |= pulse[1].length_counter ? 0x02 : 0; + result |= triangle.length_counter ? 0x04 : 0; + result |= noise.length_counter ? 0x08 : 0; + result |= dmc.length_counter ? 0x10 : 0; + result |= frame.irq_pending ? 0x40 : 0; + result |= dmc.irq_pending ? 0x80 : 0; + + frame.irq_pending = false; + set_irq_line(); + + return result; + } + + return cpu.mdr(); +} + +void APU::write(uint16 addr, uint8 data) { + const unsigned n = (addr >> 2) & 1; //pulse# + + switch(addr) { + case 0x4000: case 0x4004: + pulse[n].duty = data >> 6; + pulse[n].envelope.loop_mode = data & 0x20; + pulse[n].envelope.use_speed_as_volume = data & 0x10; + pulse[n].envelope.speed = data & 0x0f; + break; + + case 0x4001: case 0x4005: + pulse[n].sweep.enable = data & 0x80; + pulse[n].sweep.period = (data & 0x70) >> 4; + pulse[n].sweep.decrement = data & 0x08; + pulse[n].sweep.shift = data & 0x07; + pulse[n].sweep.reload = true; + break; + + case 0x4002: case 0x4006: + pulse[n].period = (pulse[n].period & 0x0700) | (data << 0); + pulse[n].sweep.pulse_period = (pulse[n].sweep.pulse_period & 0x0700) | (data << 0); + break; + + case 0x4003: case 0x4007: + pulse[n].period = (pulse[n].period & 0x00ff) | (data << 8); + pulse[n].sweep.pulse_period = (pulse[n].sweep.pulse_period & 0x00ff) | (data << 8); + + pulse[n].duty_counter = 7; + pulse[n].envelope.reload_decay = true; + + if(enabled_channels & (1 << n)) { + pulse[n].length_counter = length_counter_table[(data >> 3) & 0x1f]; + } + break; + + case 0x4008: + triangle.halt_length_counter = data & 0x80; + triangle.linear_length = data & 0x7f; + break; + + case 0x400a: + triangle.period = (triangle.period & 0x0700) | (data << 0); + break; + + case 0x400b: + triangle.period = (triangle.period & 0x00ff) | (data << 8); + + triangle.reload_linear = true; + + if(enabled_channels & (1 << 2)) { + triangle.length_counter = length_counter_table[(data >> 3) & 0x1f]; + } + break; + + case 0x400c: + noise.envelope.loop_mode = data & 0x20; + noise.envelope.use_speed_as_volume = data & 0x10; + noise.envelope.speed = data & 0x0f; + break; + + case 0x400e: + noise.short_mode = data & 0x80; + noise.period = data & 0x0f; + break; + + case 0x400f: + noise.envelope.reload_decay = true; + + if(enabled_channels & (1 << 3)) { + noise.length_counter = length_counter_table[(data >> 3) & 0x1f]; + } + break; + + case 0x4010: + dmc.irq_enable = data & 0x80; + dmc.loop_mode = data & 0x40; + dmc.period = data & 0x0f; + + dmc.irq_pending = dmc.irq_pending && dmc.irq_enable && !dmc.loop_mode; + set_irq_line(); + break; + + case 0x4011: + dmc.dac_latch = data & 0x7f; + break; + + case 0x4012: + dmc.addr_latch = data; + break; + + case 0x4013: + dmc.length_latch = data; + break; + + case 0x4015: + if((data & 0x01) == 0) pulse[0].length_counter = 0; + if((data & 0x02) == 0) pulse[1].length_counter = 0; + if((data & 0x04) == 0) triangle.length_counter = 0; + if((data & 0x08) == 0) noise.length_counter = 0; + + (data & 0x10) ? dmc.start() : dmc.stop(); + dmc.irq_pending = false; + + set_irq_line(); + enabled_channels = data & 0x1f; + break; + + case 0x4017: + frame.mode = data >> 6; + + frame.counter = 0; + if(frame.mode & 2) clock_frame_counter(); + if(frame.mode & 1) { + frame.irq_pending = false; + set_irq_line(); + } + frame.divider = FrameCounter::NtscPeriod; + break; + } +} + +signed APU::Filter::run_hipass_strong(signed sample) { + hipass_strong += ((((int64)sample << 16) - (hipass_strong >> 16)) * HiPassStrong) >> 16; + return sample - (hipass_strong >> 32); +} + +signed APU::Filter::run_hipass_weak(signed sample) { + hipass_weak += ((((int64)sample << 16) - (hipass_weak >> 16)) * HiPassWeak) >> 16; + return sample - (hipass_weak >> 32); +} + +signed APU::Filter::run_lopass(signed sample) { + lopass += ((((int64)sample << 16) - (lopass >> 16)) * LoPass) >> 16; + return (lopass >> 32); +} + +void APU::clock_frame_counter() { + frame.counter++; + + if(frame.counter & 1) { + pulse[0].clock_length(); + pulse[0].sweep.clock(0); + pulse[1].clock_length(); + pulse[1].sweep.clock(1); + triangle.clock_length(); + noise.clock_length(); + } + + pulse[0].envelope.clock(); + pulse[1].envelope.clock(); + triangle.clock_linear_length(); + noise.envelope.clock(); + + if(frame.counter == 0) { + if(frame.mode & 2) frame.divider += FrameCounter::NtscPeriod; + if(frame.mode == 0) { + frame.irq_pending = true; + set_irq_line(); + } + } +} + +void APU::clock_frame_counter_divider() { + frame.divider -= 2; + if(frame.divider <= 0) { + clock_frame_counter(); + frame.divider += FrameCounter::NtscPeriod; + } +} + +APU::APU() { + for(unsigned amp = 0; amp < 32; amp++) { + if(amp == 0) { + pulse_dac[amp] = 0; + } else { + pulse_dac[amp] = 16384.0 * 95.88 / (8128.0 / amp + 100.0); + } + } + + for(unsigned dmc_amp = 0; dmc_amp < 128; dmc_amp++) { + for(unsigned triangle_amp = 0; triangle_amp < 16; triangle_amp++) { + for(unsigned noise_amp = 0; noise_amp < 16; noise_amp++) { + if(dmc_amp == 0 && triangle_amp == 0 && noise_amp == 0) { + dmc_triangle_noise_dac[dmc_amp][triangle_amp][noise_amp] = 0; + } else { + dmc_triangle_noise_dac[dmc_amp][triangle_amp][noise_amp] + = 16384.0 * 159.79 / (100.0 + 1.0 / (triangle_amp / 8227.0 + noise_amp / 12241.0 + dmc_amp / 22638.0)); + } + } + } + } +} + +} diff --git a/nes/apu/apu.hpp b/nes/apu/apu.hpp new file mode 100755 index 00000000..9d5edd89 --- /dev/null +++ b/nes/apu/apu.hpp @@ -0,0 +1,65 @@ +struct APU : Processor { + static void Main(); + void main(); + void tick(); + void set_irq_line(); + void set_sample(int16 sample); + + void power(); + void reset(); + + uint8 read(uint16 addr); + void write(uint16 addr, uint8 data); + + void serialize(serializer&); + APU(); + + struct Filter { + enum : signed { HiPassStrong = 225574, HiPassWeak = 57593, LoPass = 86322413 }; + + int64 hipass_strong; + int64 hipass_weak; + int64 lopass; + + signed run_hipass_strong(signed sample); + signed run_hipass_weak(signed sample); + signed run_lopass(signed sample); + void serialize(serializer&); + } filter; + + #include "envelope.hpp" + #include "sweep.hpp" + #include "pulse.hpp" + #include "triangle.hpp" + #include "noise.hpp" + #include "dmc.hpp" + + struct FrameCounter { + enum : unsigned { NtscPeriod = 14915 }; //~(21.477MHz / 6 / 240hz) + + bool irq_pending; + + uint2 mode; + uint2 counter; + signed divider; + + void serialize(serializer&); + } frame; + + void clock_frame_counter(); + void clock_frame_counter_divider(); + + uint8 enabled_channels; + int16 cartridge_sample; + + int16 pulse_dac[32]; + int16 dmc_triangle_noise_dac[128][16][16]; + + static const uint8 length_counter_table[32]; + static const uint16 ntsc_dmc_period_table[16]; + static const uint16 pal_dmc_period_table[16]; + static const uint16 ntsc_noise_period_table[16]; + static const uint16 pal_noise_period_table[16]; +}; + +extern APU apu; diff --git a/nes/apu/dmc.cpp b/nes/apu/dmc.cpp new file mode 100755 index 00000000..6e0031b9 --- /dev/null +++ b/nes/apu/dmc.cpp @@ -0,0 +1,117 @@ +void APU::DMC::start() { + if(length_counter == 0) { + read_addr = 0x4000 + (addr_latch << 6); + length_counter = (length_latch << 4) + 1; + } +} + +void APU::DMC::stop() { + length_counter = 0; + dma_delay_counter = 0; + cpu.set_rdy_line(1); + cpu.set_rdy_addr({ false, 0u }); +} + +uint8 APU::DMC::clock() { + uint8 result = dac_latch; + + if(dma_delay_counter > 0) { + dma_delay_counter--; + + if(dma_delay_counter == 1) { + cpu.set_rdy_addr({ true, uint16(0x8000 | read_addr) }); + } else if(dma_delay_counter == 0) { + cpu.set_rdy_line(1); + cpu.set_rdy_addr({ false, 0u }); + + dma_buffer = cpu.mdr(); + have_dma_buffer = true; + length_counter--; + read_addr++; + + if(length_counter == 0) { + if(loop_mode) { + start(); + } else if(irq_enable) { + irq_pending = true; + apu.set_irq_line(); + } + } + } + } + + if(--period_counter == 0) { + if(have_sample) { + signed delta = (((sample >> bit_counter) & 1) << 2) - 2; + unsigned data = dac_latch + delta; + if((data & 0x80) == 0) dac_latch = data; + } + + if(++bit_counter == 0) { + if(have_dma_buffer) { + have_sample = true; + sample = dma_buffer; + have_dma_buffer = false; + } else { + have_sample = false; + } + } + + period_counter = ntsc_dmc_period_table[period]; + } + + if(length_counter > 0 && have_dma_buffer == false && dma_delay_counter == 0) { + cpu.set_rdy_line(0); + dma_delay_counter = 4; + } + + return result; +} + +void APU::DMC::power() { +} + +void APU::DMC::reset() { + length_counter = 0; + irq_pending = 0; + + period = 0; + period_counter = ntsc_dmc_period_table[0]; + irq_enable = 0; + loop_mode = 0; + dac_latch = 0; + addr_latch = 0; + length_latch = 0; + read_addr = 0; + dma_delay_counter = 0; + bit_counter = 0; + have_dma_buffer = 0; + dma_buffer = 0; + have_sample = 0; + sample = 0; +} + +void APU::DMC::serialize(serializer &s) { + s.integer(length_counter); + s.integer(irq_pending); + + s.integer(period); + s.integer(period_counter); + + s.integer(irq_enable); + s.integer(loop_mode); + + s.integer(dac_latch); + s.integer(addr_latch); + s.integer(length_latch); + + s.integer(read_addr); + s.integer(dma_delay_counter); + + s.integer(bit_counter); + s.integer(have_dma_buffer); + s.integer(dma_buffer); + + s.integer(have_sample); + s.integer(sample); +} diff --git a/nes/apu/dmc.hpp b/nes/apu/dmc.hpp new file mode 100755 index 00000000..5fcce929 --- /dev/null +++ b/nes/apu/dmc.hpp @@ -0,0 +1,32 @@ +struct DMC { + unsigned length_counter; + bool irq_pending; + + uint4 period; + unsigned period_counter; + + bool irq_enable; + bool loop_mode; + + uint8 dac_latch; + uint8 addr_latch; + uint8 length_latch; + + uint15 read_addr; + unsigned dma_delay_counter; + + uint3 bit_counter; + bool have_dma_buffer; + uint8 dma_buffer; + + bool have_sample; + uint8 sample; + + void start(); + void stop(); + uint8 clock(); + + void power(); + void reset(); + void serialize(serializer&); +} dmc; diff --git a/nes/apu/envelope.cpp b/nes/apu/envelope.cpp new file mode 100755 index 00000000..08b56ee8 --- /dev/null +++ b/nes/apu/envelope.cpp @@ -0,0 +1,39 @@ +unsigned APU::Envelope::volume() const { + return use_speed_as_volume ? speed : decay_volume; +} + +void APU::Envelope::clock() { + if(reload_decay) { + reload_decay = false; + decay_volume = 0x0f; + decay_counter = speed + 1; + return; + } + + if(--decay_counter == 0) { + decay_counter = speed + 1; + if(decay_volume || loop_mode) decay_volume--; + } +} + +void APU::Envelope::power() { +} + +void APU::Envelope::reset() { + speed = 0; + use_speed_as_volume = 0; + loop_mode = 0; + reload_decay = 0; + decay_counter = 0; + decay_volume = 0; +} + +void APU::Envelope::serialize(serializer &s) { + s.integer(speed); + s.integer(use_speed_as_volume); + s.integer(loop_mode); + + s.integer(reload_decay); + s.integer(decay_counter); + s.integer(decay_volume); +} diff --git a/nes/apu/envelope.hpp b/nes/apu/envelope.hpp new file mode 100755 index 00000000..054d2fef --- /dev/null +++ b/nes/apu/envelope.hpp @@ -0,0 +1,16 @@ +struct Envelope { + uint4 speed; + bool use_speed_as_volume; + bool loop_mode; + + bool reload_decay; + uint8 decay_counter; + uint4 decay_volume; + + unsigned volume() const; + void clock(); + + void power(); + void reset(); + void serialize(serializer&); +}; diff --git a/nes/apu/noise.cpp b/nes/apu/noise.cpp new file mode 100755 index 00000000..74173802 --- /dev/null +++ b/nes/apu/noise.cpp @@ -0,0 +1,57 @@ +void APU::Noise::clock_length() { + if(envelope.loop_mode == 0) { + if(length_counter > 0) length_counter--; + } +} + +uint8 APU::Noise::clock() { + if(length_counter == 0) return 0; + + uint8 result = (lfsr & 1) ? envelope.volume() : 0; + + if(--period_counter == 0) { + unsigned feedback; + + if(short_mode) { + feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 6) & 1); + } else { + feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 1) & 1); + } + + lfsr = (lfsr >> 1) | (feedback << 14); + period_counter = apu.ntsc_noise_period_table[period]; + } + + return result; +} + +void APU::Noise::power() { +} + +void APU::Noise::reset() { + length_counter = 0; + + envelope.speed = 0; + envelope.use_speed_as_volume = 0; + envelope.loop_mode = 0; + envelope.reload_decay = 0; + envelope.decay_counter = 0; + envelope.decay_volume = 0; + + period = 0; + period_counter = 1; + short_mode = 0; + lfsr = 1; +} + +void APU::Noise::serialize(serializer &s) { + s.integer(length_counter); + + envelope.serialize(s); + + s.integer(period); + s.integer(period_counter); + + s.integer(short_mode); + s.integer(lfsr); +} diff --git a/nes/apu/noise.hpp b/nes/apu/noise.hpp new file mode 100755 index 00000000..6684893a --- /dev/null +++ b/nes/apu/noise.hpp @@ -0,0 +1,18 @@ +struct Noise { + unsigned length_counter; + + Envelope envelope; + + uint4 period; + unsigned period_counter; + + bool short_mode; + uint15 lfsr; + + void clock_length(); + uint8 clock(); + + void power(); + void reset(); + void serialize(serializer&); +} noise; diff --git a/nes/apu/pulse.cpp b/nes/apu/pulse.cpp new file mode 100755 index 00000000..e8305617 --- /dev/null +++ b/nes/apu/pulse.cpp @@ -0,0 +1,51 @@ +void APU::Pulse::clock_length() { + if(envelope.loop_mode == 0) { + if(length_counter) length_counter--; + } +} + +uint8 APU::Pulse::clock() { + if(sweep.check_period() == false) return 0; + if(length_counter == 0) return 0; + + static const unsigned duty_table[] = { 1, 2, 4, 6 }; + uint8 result = (duty_counter < duty_table[duty]) ? envelope.volume() : 0; + if(sweep.pulse_period < 0x008) result = 0; + + if(--period_counter == 0) { + period_counter = (sweep.pulse_period + 1) * 2; + duty_counter++; + } + + return result; +} + +void APU::Pulse::power() { + envelope.power(); + sweep.power(); +} + +void APU::Pulse::reset() { + envelope.reset(); + sweep.reset(); + + length_counter = 0; + + duty = 0; + duty_counter = 0; + period = 0; + period_counter = 1; +} + +void APU::Pulse::serialize(serializer &s) { + s.integer(length_counter); + + envelope.serialize(s); + sweep.serialize(s); + + s.integer(duty); + s.integer(duty_counter); + + s.integer(period); + s.integer(period_counter); +} diff --git a/nes/apu/pulse.hpp b/nes/apu/pulse.hpp new file mode 100755 index 00000000..6c41cea4 --- /dev/null +++ b/nes/apu/pulse.hpp @@ -0,0 +1,20 @@ +struct Pulse { + unsigned length_counter; + + Envelope envelope; + Sweep sweep; + + uint2 duty; + uint3 duty_counter; + + uint11 period; + unsigned period_counter; + + void clock_length(); + bool check_period(); + uint8 clock(); + + void power(); + void reset(); + void serialize(serializer&); +} pulse[2]; diff --git a/nes/apu/serialization.cpp b/nes/apu/serialization.cpp new file mode 100755 index 00000000..7043769f --- /dev/null +++ b/nes/apu/serialization.cpp @@ -0,0 +1,28 @@ +void APU::serialize(serializer &s) { + Processor::serialize(s); + + filter.serialize(s); + + pulse[0].serialize(s); + pulse[1].serialize(s); + triangle.serialize(s); + dmc.serialize(s); + frame.serialize(s); + + s.integer(enabled_channels); + s.integer(cartridge_sample); +} + +void APU::Filter::serialize(serializer &s) { + s.integer(hipass_strong); + s.integer(hipass_weak); + s.integer(lopass); +} + +void APU::FrameCounter::serialize(serializer &s) { + s.integer(irq_pending); + + s.integer(mode); + s.integer(counter); + s.integer(divider); +} diff --git a/nes/apu/sweep.cpp b/nes/apu/sweep.cpp new file mode 100755 index 00000000..8c0211b9 --- /dev/null +++ b/nes/apu/sweep.cpp @@ -0,0 +1,53 @@ +bool APU::Sweep::check_period() { + if(pulse_period > 0x7ff) return false; + + if(decrement == 0) { + if((pulse_period + (pulse_period >> shift)) & 0x800) return false; + } + + return true; +} + +void APU::Sweep::clock(unsigned channel) { + if(--counter == 0) { + counter = period + 1; + if(enable && shift && pulse_period > 8) { + signed delta = pulse_period >> shift; + + if(decrement) { + pulse_period -= delta; + if(channel == 0) pulse_period--; + } else if((pulse_period + delta) < 0x800) { + pulse_period += delta; + } + } + } + + if(reload) { + reload = false; + counter = period + 1; + } +} + +void APU::Sweep::power() { + shift = 0; + decrement = 0; + period = 0; + counter = 1; + enable = 0; + reload = 0; + pulse_period = 0; +} + +void APU::Sweep::reset() { +} + +void APU::Sweep::serialize(serializer &s) { + s.integer(shift); + s.integer(decrement); + s.integer(period); + s.integer(counter); + s.integer(enable); + s.integer(reload); + s.integer(pulse_period); +} diff --git a/nes/apu/sweep.hpp b/nes/apu/sweep.hpp new file mode 100755 index 00000000..69137b5b --- /dev/null +++ b/nes/apu/sweep.hpp @@ -0,0 +1,16 @@ +struct Sweep { + uint8 shift; + bool decrement; + uint3 period; + uint8 counter; + bool enable; + bool reload; + uint11 pulse_period; + + bool check_period(); + void clock(unsigned channel); + + void power(); + void reset(); + void serialize(serializer&); +}; diff --git a/nes/apu/triangle.cpp b/nes/apu/triangle.cpp new file mode 100755 index 00000000..0b0b1358 --- /dev/null +++ b/nes/apu/triangle.cpp @@ -0,0 +1,58 @@ +void APU::Triangle::clock_length() { + if(halt_length_counter == 0) { + if(length_counter > 0) length_counter--; + } +} + +void APU::Triangle::clock_linear_length() { + if(reload_linear) { + linear_length_counter = linear_length; + } else if(linear_length_counter) { + linear_length_counter--; + } + + if(halt_length_counter == 0) reload_linear = false; +} + +uint8 APU::Triangle::clock() { + uint8 result = step_counter & 0x0f; + if((step_counter & 0x10) == 0) result ^= 0x0f; + if(length_counter == 0 || linear_length_counter == 0) return result; + + if(--period_counter == 0) { + step_counter++; + period_counter = period + 1; + } + + return result; +} + +void APU::Triangle::power() { + reset(); +} + +void APU::Triangle::reset() { + length_counter = 0; + + linear_length = 0; + halt_length_counter = 0; + period = 0; + period_counter = 1; + step_counter = 0; + linear_length_counter = 0; + reload_linear = 0; +} + +void APU::Triangle::serialize(serializer &s) { + s.integer(length_counter); + + s.integer(linear_length); + s.integer(halt_length_counter); + + s.integer(period); + s.integer(period_counter); + + s.integer(step_counter); + s.integer(linear_length_counter); + s.integer(reload_linear); +} diff --git a/nes/apu/triangle.hpp b/nes/apu/triangle.hpp new file mode 100755 index 00000000..ef88a5ca --- /dev/null +++ b/nes/apu/triangle.hpp @@ -0,0 +1,21 @@ +struct Triangle { + unsigned length_counter; + + uint8 linear_length; + bool halt_length_counter; + + uint11 period; + unsigned period_counter; + + uint5 step_counter; + uint8 linear_length_counter; + bool reload_linear; + + void clock_length(); + void clock_linear_length(); + uint8 clock(); + + void power(); + void reset(); + void serialize(serializer&); +} triangle; diff --git a/nes/cartridge/board/bandai-fcg.cpp b/nes/cartridge/board/bandai-fcg.cpp new file mode 100755 index 00000000..f4c69291 --- /dev/null +++ b/nes/cartridge/board/bandai-fcg.cpp @@ -0,0 +1,117 @@ +//BANDAI-FCG + +struct BandaiFCG : Board { + +uint8 chr_bank[8]; +uint8 prg_bank; +uint2 mirror; +bool irq_counter_enable; +uint16 irq_counter; +uint16 irq_latch; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_counter_enable) { + if(--irq_counter == 0xffff) { + cpu.set_irq_line(1); + irq_counter_enable = false; + } + } + + tick(); + } +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); + case 2: return 0x0000 | (addr & 0x03ff); + case 3: return 0x0400 | (addr & 0x03ff); + } +} + +uint8 prg_read(unsigned addr) { + if(addr & 0x8000) { + bool region = addr & 0x4000; + unsigned bank = (region == 0 ? prg_bank : 0x0f); + return prgrom.read((bank << 14) | (addr & 0x3fff)); + } + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr >= 0x6000) { + switch(addr & 15) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + chr_bank[addr & 7] = data; + break; + case 0x08: + prg_bank = data & 0x0f; + break; + case 0x09: + mirror = data & 0x03; + break; + case 0x0a: + cpu.set_irq_line(0); + irq_counter_enable = data & 0x01; + irq_counter = irq_latch; + break; + case 0x0b: + irq_latch = (irq_latch & 0xff00) | (data << 0); + break; + case 0x0c: + irq_latch = (irq_latch & 0x00ff) | (data << 8); + break; + case 0x0d: + //TODO: serial EEPROM support + break; + } + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr)); + addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff); + return Board::chr_read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data); + addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff); + return Board::chr_write(addr, data); +} + +void power() { + reset(); +} + +void reset() { + for(auto &n : chr_bank) n = 0; + prg_bank = 0; + mirror = 0; + irq_counter_enable = 0; + irq_counter = 0; + irq_latch = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + + s.array(chr_bank); + s.integer(prg_bank); + s.integer(mirror); + s.integer(irq_counter_enable); + s.integer(irq_counter); + s.integer(irq_latch); +} + +BandaiFCG(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { +} + +}; diff --git a/nes/cartridge/board/board.cpp b/nes/cartridge/board/board.cpp new file mode 100755 index 00000000..00e5917b --- /dev/null +++ b/nes/cartridge/board/board.cpp @@ -0,0 +1,166 @@ +#include "bandai-fcg.cpp" +#include "konami-vrc1.cpp" +#include "konami-vrc2.cpp" +#include "konami-vrc3.cpp" +#include "konami-vrc4.cpp" +#include "konami-vrc6.cpp" +#include "konami-vrc7.cpp" +#include "nes-axrom.cpp" +#include "nes-bnrom.cpp" +#include "nes-cnrom.cpp" +#include "nes-exrom.cpp" +#include "nes-fxrom.cpp" +#include "nes-gxrom.cpp" +#include "nes-hkrom.cpp" +#include "nes-nrom.cpp" +#include "nes-pxrom.cpp" +#include "nes-sxrom.cpp" +#include "nes-txrom.cpp" +#include "nes-uxrom.cpp" +#include "sunsoft-5b.cpp" + +uint8 Board::Memory::read(unsigned addr) const { + return data[mirror(addr, size)]; +} + +void Board::Memory::write(unsigned addr, uint8 byte) { + if(writable) data[mirror(addr, size)] = byte; +} + +unsigned Board::mirror(unsigned addr, unsigned size) { + unsigned base = 0; + if(size) { + unsigned mask = 1 << 23; + while(addr >= size) { + while(!(addr & mask)) mask >>= 1; + addr -= mask; + if(size > mask) { + size -= mask; + base += mask; + } + mask >>= 1; + } + base += addr; + } + return base; +} + +void Board::main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + cartridge.clock += 12 * 4095; + tick(); + } +} + +void Board::tick() { + cartridge.clock += 12; + if(cartridge.clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); +} + +uint8 Board::chr_read(unsigned addr) { + if(chrram.size) return chrram.data[mirror(addr, chrram.size)]; + if(chrrom.size) return chrrom.data[mirror(addr, chrrom.size)]; + return 0u; +} + +void Board::chr_write(unsigned addr, uint8 data) { + if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data; +} + +Board::Memory& Board::memory() { + return prgram; +} + +void Board::power() { +} + +void Board::reset() { +} + +void Board::serialize(serializer &s) { + if(prgram.size) s.array(prgram.data, prgram.size); + if(chrram.size) s.array(chrram.data, chrram.size); +} + +Board::Board(BML::Node &board, const uint8_t *data, unsigned size) { + information.type = board["type"].value; + information.battery = board["prg"]["battery"].value; + + prgrom.size = decimal(board["prg"]["rom"].value); + prgram.size = decimal(board["prg"]["ram"].value); + chrrom.size = decimal(board["chr"]["rom"].value); + chrram.size = decimal(board["chr"]["ram"].value); + + if(prgrom.size) prgrom.data = new uint8[prgrom.size](); + if(prgram.size) prgram.data = new uint8[prgram.size](); + if(chrrom.size) chrrom.data = new uint8[chrrom.size](); + if(chrram.size) chrram.data = new uint8[chrram.size](); + + if(prgrom.size) memcpy(prgrom.data, data, prgrom.size); + if(chrrom.size) memcpy(chrrom.data, data + prgrom.size, chrrom.size); + + prgram.writable = true; + chrram.writable = true; +} + +Board::~Board() { +} + +Board* Board::load(const string &markup, const uint8_t *data, unsigned size) { + BML::Document document(markup); + auto &board = document["cartridge"]["board"]; + string type = board["type"].value; + + if(type == "BANDAI-FCG") return new BandaiFCG(board, data, size); + + if(type == "KONAMI-VRC-1") return new KonamiVRC1(board, data, size); + if(type == "KONAMI-VRC-2") return new KonamiVRC2(board, data, size); + if(type == "KONAMI-VRC-3") return new KonamiVRC3(board, data, size); + if(type == "KONAMI-VRC-4") return new KonamiVRC4(board, data, size); + if(type == "KONAMI-VRC-6") return new KonamiVRC6(board, data, size); + if(type == "KONAMI-VRC-7") return new KonamiVRC7(board, data, size); + + if(type == "NES-AMROM" ) return new NES_AxROM(board, data, size); + if(type == "NES-ANROM" ) return new NES_AxROM(board, data, size); + if(type == "NES-AN1ROM" ) return new NES_AxROM(board, data, size); + if(type == "NES-AOROM" ) return new NES_AxROM(board, data, size); + + if(type == "NES-BNROM" ) return new NES_BNROM(board, data, size); + + if(type == "NES-CNROM" ) return new NES_CNROM(board, data, size); + + if(type == "NES-EKROM" ) return new NES_ExROM(board, data, size); + if(type == "NES-ELROM" ) return new NES_ExROM(board, data, size); + if(type == "NES-ETROM" ) return new NES_ExROM(board, data, size); + if(type == "NES-EWROM" ) return new NES_ExROM(board, data, size); + + if(type == "NES-FJROM" ) return new NES_FxROM(board, data, size); + if(type == "NES-FKROM" ) return new NES_FxROM(board, data, size); + + if(type == "NES-GNROM" ) return new NES_GxROM(board, data, size); + if(type == "NES-MHROM" ) return new NES_GxROM(board, data, size); + + if(type == "NES-HKROM" ) return new NES_HKROM(board, data, size); + + if(type == "NES-NROM-128") return new NES_NROM(board, data, size); + if(type == "NES-NROM-256") return new NES_NROM(board, data, size); + + if(type == "NES-PEEOROM" ) return new NES_PxROM(board, data, size); + if(type == "NES-PNROM" ) return new NES_PxROM(board, data, size); + + if(type == "NES-SNROM" ) return new NES_SxROM(board, data, size); + if(type == "NES-SXROM" ) return new NES_SxROM(board, data, size); + + if(type == "NES-TLROM" ) return new NES_TxROM(board, data, size); + + if(type == "NES-UNROM" ) return new NES_UxROM(board, data, size); + if(type == "NES-UOROM" ) return new NES_UxROM(board, data, size); + + if(type == "SUNSOFT-5B" ) return new Sunsoft5B(board, data, size); + + return nullptr; +} diff --git a/nes/cartridge/board/board.hpp b/nes/cartridge/board/board.hpp new file mode 100755 index 00000000..0cd8ce91 --- /dev/null +++ b/nes/cartridge/board/board.hpp @@ -0,0 +1,48 @@ +struct Board { + struct Memory { + uint8_t *data; + unsigned size; + bool writable; + + inline uint8 read(unsigned addr) const; + inline void write(unsigned addr, uint8 data); + + inline Memory(uint8_t *data, unsigned size) : data(data), size(size) {} + inline Memory() : data(nullptr), size(0u), writable(false) {} + inline ~Memory() { if(data) delete[] data; } + }; + + static unsigned mirror(unsigned addr, unsigned size); + + virtual void main(); + virtual void tick(); + + virtual uint8 prg_read(unsigned addr) = 0; + virtual void prg_write(unsigned addr, uint8 data) = 0; + + virtual uint8 chr_read(unsigned addr); + virtual void chr_write(unsigned addr, uint8 data); + + virtual inline void scanline(unsigned y) {} + + virtual Memory& memory(); + + virtual void power(); + virtual void reset(); + + virtual void serialize(serializer&); + Board(BML::Node &board, const uint8_t *data, unsigned size); + virtual ~Board(); + + static Board* load(const string &markup, const uint8_t *data, unsigned size); + + struct Information { + string type; + bool battery; + } information; + + Memory prgrom; + Memory prgram; + Memory chrrom; + Memory chrram; +}; diff --git a/nes/cartridge/board/konami-vrc1.cpp b/nes/cartridge/board/konami-vrc1.cpp new file mode 100755 index 00000000..d473e6ba --- /dev/null +++ b/nes/cartridge/board/konami-vrc1.cpp @@ -0,0 +1,40 @@ +struct KonamiVRC1 : Board { + +VRC1 vrc1; + +uint8 prg_read(unsigned addr) { + if(addr & 0x8000) return prgrom.read(vrc1.prg_addr(addr)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr & 0x8000) return vrc1.reg_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(vrc1.ciram_addr(addr)); + return Board::chr_read(vrc1.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(vrc1.ciram_addr(addr), data); + return Board::chr_write(vrc1.chr_addr(addr), data); +} + +void power() { + vrc1.power(); +} + +void reset() { + vrc1.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + vrc1.serialize(s); +} + +KonamiVRC1(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc1(*this) { +} + +}; diff --git a/nes/cartridge/board/konami-vrc2.cpp b/nes/cartridge/board/konami-vrc2.cpp new file mode 100755 index 00000000..164fe848 --- /dev/null +++ b/nes/cartridge/board/konami-vrc2.cpp @@ -0,0 +1,57 @@ +struct KonamiVRC2 : Board { + +struct Settings { + struct Pinout { + unsigned a0; + unsigned a1; + } pinout; +} settings; + +VRC2 vrc2; + +uint8 prg_read(unsigned addr) { + if(addr < 0x6000) return cpu.mdr(); + if(addr < 0x8000) return vrc2.ram_read(addr); + return prgrom.read(vrc2.prg_addr(addr)); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr < 0x6000) return; + if(addr < 0x8000) return vrc2.ram_write(addr, data); + + bool a0 = (addr & settings.pinout.a0); + bool a1 = (addr & settings.pinout.a1); + addr &= 0xfff0; + addr |= (a0 << 0) | (a1 << 1); + return vrc2.reg_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(vrc2.ciram_addr(addr)); + return Board::chr_read(vrc2.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(vrc2.ciram_addr(addr), data); + return Board::chr_write(vrc2.chr_addr(addr), data); +} + +void power() { + vrc2.power(); +} + +void reset() { + vrc2.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + vrc2.serialize(s); +} + +KonamiVRC2(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc2(*this) { + settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].value); + settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].value); +} + +}; diff --git a/nes/cartridge/board/konami-vrc3.cpp b/nes/cartridge/board/konami-vrc3.cpp new file mode 100755 index 00000000..9aef5df4 --- /dev/null +++ b/nes/cartridge/board/konami-vrc3.cpp @@ -0,0 +1,57 @@ +struct KonamiVRC3 : Board { + +struct Settings { + bool mirror; //0 = horizontal, 1 = vertical +} settings; + +VRC3 vrc3; + +void main() { + vrc3.main(); +} + +uint8 prg_read(unsigned addr) { + if((addr & 0xe000) == 0x6000) return prgram.read(addr & 0x1fff); + if(addr & 0x8000) return prgrom.read(vrc3.prg_addr(addr)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xe000) == 0x6000) return prgram.write(addr & 0x1fff, data); + if(addr & 0x8000) return vrc3.reg_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_read(addr & 0x07ff); + } + return chrram.read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_write(addr & 0x07ff, data); + } + return chrram.write(addr, data); +} + +void power() { + vrc3.power(); +} + +void reset() { + vrc3.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + vrc3.serialize(s); +} + +KonamiVRC3(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc3(*this) { + settings.mirror = board["mirror"].value == "vertical" ? 1 : 0; +} + +}; diff --git a/nes/cartridge/board/konami-vrc4.cpp b/nes/cartridge/board/konami-vrc4.cpp new file mode 100755 index 00000000..fa8fa4b8 --- /dev/null +++ b/nes/cartridge/board/konami-vrc4.cpp @@ -0,0 +1,61 @@ +struct KonamiVRC4 : Board { + +struct Settings { + struct Pinout { + unsigned a0; + unsigned a1; + } pinout; +} settings; + +VRC4 vrc4; + +void main() { + return vrc4.main(); +} + +uint8 prg_read(unsigned addr) { + if(addr < 0x6000) return cpu.mdr(); + if(addr < 0x8000) return prgram.read(addr); + return prgrom.read(vrc4.prg_addr(addr)); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr < 0x6000) return; + if(addr < 0x8000) return prgram.write(addr, data); + + bool a0 = (addr & settings.pinout.a0); + bool a1 = (addr & settings.pinout.a1); + addr &= 0xfff0; + addr |= (a1 << 1) | (a0 << 0); + return vrc4.reg_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(vrc4.ciram_addr(addr)); + return Board::chr_read(vrc4.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(vrc4.ciram_addr(addr), data); + return Board::chr_write(vrc4.chr_addr(addr), data); +} + +void power() { + vrc4.power(); +} + +void reset() { + vrc4.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + vrc4.serialize(s); +} + +KonamiVRC4(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc4(*this) { + settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].value); + settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].value); +} + +}; diff --git a/nes/cartridge/board/konami-vrc6.cpp b/nes/cartridge/board/konami-vrc6.cpp new file mode 100755 index 00000000..6ab17b2e --- /dev/null +++ b/nes/cartridge/board/konami-vrc6.cpp @@ -0,0 +1,42 @@ +struct KonamiVRC6 : Board { + +VRC6 vrc6; + +uint8 prg_read(unsigned addr) { + if((addr & 0xe000) == 0x6000) return vrc6.ram_read(addr); + if(addr & 0x8000) return prgrom.read(vrc6.prg_addr(addr)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xe000) == 0x6000) return vrc6.ram_write(addr, data); + if(addr & 0x8000) { + addr = (addr & 0xf003); + if(prgram.size) addr = (addr & ~3) | ((addr & 2) >> 1) | ((addr & 1) << 1); + return vrc6.reg_write(addr, data); + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(vrc6.ciram_addr(addr)); + return Board::chr_read(vrc6.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(vrc6.ciram_addr(addr), data); + return Board::chr_write(vrc6.chr_addr(addr), data); +} + +void serialize(serializer &s) { + Board::serialize(s); + vrc6.serialize(s); +} + +void main() { vrc6.main(); } +void power() { vrc6.power(); } +void reset() { vrc6.reset(); } + +KonamiVRC6(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc6(*this) { +} + +}; diff --git a/nes/cartridge/board/konami-vrc7.cpp b/nes/cartridge/board/konami-vrc7.cpp new file mode 100755 index 00000000..b085a3e4 --- /dev/null +++ b/nes/cartridge/board/konami-vrc7.cpp @@ -0,0 +1,47 @@ +struct KonamiVRC7 : Board { + +VRC7 vrc7; + +void main() { + return vrc7.main(); +} + +uint8 prg_read(unsigned addr) { + if(addr < 0x6000) return cpu.mdr(); + if(addr < 0x8000) return prgram.read(addr); + return prgrom.read(vrc7.prg_addr(addr)); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr < 0x6000) return; + if(addr < 0x8000) return prgram.write(addr, data); + return vrc7.reg_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(vrc7.ciram_addr(addr)); + return chrram.read(vrc7.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(vrc7.ciram_addr(addr), data); + return chrram.write(vrc7.chr_addr(addr), data); +} + +void power() { + vrc7.power(); +} + +void reset() { + vrc7.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + vrc7.serialize(s); +} + +KonamiVRC7(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc7(*this) { +} + +}; diff --git a/nes/cartridge/board/nes-axrom.cpp b/nes/cartridge/board/nes-axrom.cpp new file mode 100755 index 00000000..379d4ae5 --- /dev/null +++ b/nes/cartridge/board/nes-axrom.cpp @@ -0,0 +1,51 @@ +//NES-AMROM +//NES-ANROM +//NES-AN1ROM +//NES-AOROM + +struct NES_AxROM : Board { + +uint4 prg_bank; +bool mirror_select; + +uint8 prg_read(unsigned addr) { + if(addr & 0x8000) return prgrom.read((prg_bank << 15) | (addr & 0x7fff)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr & 0x8000) { + prg_bank = data & 0x0f; + mirror_select = data & 0x10; + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read((mirror_select << 10) | (addr & 0x03ff)); + return Board::chr_read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write((mirror_select << 10) | (addr & 0x03ff), data); + return Board::chr_write(addr, data); +} + +void power() { +} + +void reset() { + prg_bank = 0x0f; + mirror_select = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + + s.integer(prg_bank); + s.integer(mirror_select); +} + +NES_AxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { +} + +}; diff --git a/nes/cartridge/board/nes-bnrom.cpp b/nes/cartridge/board/nes-bnrom.cpp new file mode 100755 index 00000000..013de500 --- /dev/null +++ b/nes/cartridge/board/nes-bnrom.cpp @@ -0,0 +1,52 @@ +//NES-BN-ROM-01 + +struct NES_BNROM : Board { + +struct Settings { + bool mirror; //0 = horizontal, 1 = vertical +} settings; + +uint2 prg_bank; + +uint8 prg_read(unsigned addr) { + if(addr & 0x8000) return prgrom.read((prg_bank << 15) | (addr & 0x7fff)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr & 0x8000) prg_bank = data & 0x03; +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_read(addr); + } + return Board::chr_read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_write(addr, data); + } + return Board::chr_write(addr, data); +} + +void power() { +} + +void reset() { + prg_bank = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + s.integer(prg_bank); +} + +NES_BNROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { + settings.mirror = board["mirror"].value == "vertical" ? 1 : 0; +} + +}; diff --git a/nes/cartridge/board/nes-cnrom.cpp b/nes/cartridge/board/nes-cnrom.cpp new file mode 100755 index 00000000..85ff4ef9 --- /dev/null +++ b/nes/cartridge/board/nes-cnrom.cpp @@ -0,0 +1,54 @@ +//NES-CNROM + +struct NES_CNROM : Board { + +struct Settings { + bool mirror; //0 = horizontal, 1 = vertical +} settings; + +uint2 chr_bank; + +uint8 prg_read(unsigned addr) { + if(addr & 0x8000) return prgrom.read(addr & 0x7fff); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr & 0x8000) chr_bank = data & 0x03; +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_read(addr & 0x07ff); + } + addr = (chr_bank * 0x2000) + (addr & 0x1fff); + return Board::chr_read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_write(addr & 0x07ff, data); + } + addr = (chr_bank * 0x2000) + (addr & 0x1fff); + Board::chr_write(addr, data); +} + +void power() { +} + +void reset() { + chr_bank = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + s.integer(chr_bank); +} + +NES_CNROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { + settings.mirror = board["mirror"].value == "vertical" ? 1 : 0; +} + +}; diff --git a/nes/cartridge/board/nes-exrom.cpp b/nes/cartridge/board/nes-exrom.cpp new file mode 100755 index 00000000..e7d4aac8 --- /dev/null +++ b/nes/cartridge/board/nes-exrom.cpp @@ -0,0 +1,53 @@ +struct NES_ExROM : Board { + +enum class Revision : unsigned { + EKROM, + ELROM, + ETROM, + EWROM, +} revision; + +MMC5 mmc5; + +void main() { + mmc5.main(); +} + +uint8 prg_read(unsigned addr) { + return mmc5.prg_read(addr); +} + +void prg_write(unsigned addr, uint8 data) { + mmc5.prg_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + return mmc5.chr_read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + mmc5.chr_write(addr, data); +} + +void scanline(unsigned y) { + mmc5.scanline(y); +} + +void power() { + mmc5.power(); +} + +void reset() { + mmc5.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + mmc5.serialize(s); +} + +NES_ExROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc5(*this) { + revision = Revision::ELROM; +} + +}; diff --git a/nes/cartridge/board/nes-fxrom.cpp b/nes/cartridge/board/nes-fxrom.cpp new file mode 100755 index 00000000..891fef76 --- /dev/null +++ b/nes/cartridge/board/nes-fxrom.cpp @@ -0,0 +1,91 @@ +//MMC4 + +struct NES_FxROM : Board { + +enum Revision : unsigned { + FJROM, + FKROM, +} revision; + +uint4 prg_bank; +uint5 chr_bank[2][2]; +bool mirror; +bool latch[2]; + +uint8 prg_read(unsigned addr) { + if(addr < 0x6000) return cpu.mdr(); + if(addr < 0x8000) return prgram.read(addr); + unsigned bank = addr < 0xc000 ? prg_bank : (uint4)0x0f; + return prgrom.read((bank * 0x4000) | (addr & 0x3fff)); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr < 0x6000) return; + if(addr < 0x8000) return prgram.write(addr, data); + + switch(addr & 0xf000) { + case 0xa000: prg_bank = data & 0x0f; break; + case 0xb000: chr_bank[0][0] = data & 0x1f; break; + case 0xc000: chr_bank[0][1] = data & 0x1f; break; + case 0xd000: chr_bank[1][0] = data & 0x1f; break; + case 0xe000: chr_bank[1][1] = data & 0x1f; break; + case 0xf000: mirror = data & 0x01; break; + } +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr)); + bool region = addr & 0x1000; + unsigned bank = chr_bank[region][latch[region]]; + if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0; + if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; + return Board::chr_read((bank * 0x1000) | (addr & 0x0fff)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data); + bool region = addr & 0x1000; + unsigned bank = chr_bank[region][latch[region]]; + if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0; + if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; + return Board::chr_write((bank * 0x1000) | (addr & 0x0fff), data); +} + +void power() { +} + +void reset() { + prg_bank = 0; + chr_bank[0][0] = 0; + chr_bank[0][1] = 0; + chr_bank[1][0] = 0; + chr_bank[1][1] = 0; + mirror = 0; + latch[0] = 0; + latch[1] = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + + s.integer(prg_bank); + s.integer(chr_bank[0][0]); + s.integer(chr_bank[0][1]); + s.integer(chr_bank[1][0]); + s.integer(chr_bank[1][1]); + s.integer(mirror); + s.array(latch); +} + +NES_FxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { + revision = Revision::FKROM; +} + +}; diff --git a/nes/cartridge/board/nes-gxrom.cpp b/nes/cartridge/board/nes-gxrom.cpp new file mode 100755 index 00000000..3d0ecbe3 --- /dev/null +++ b/nes/cartridge/board/nes-gxrom.cpp @@ -0,0 +1,61 @@ +//NES-GNROM +//NES-MHROM + +struct NES_GxROM : Board { + +struct Settings { + bool mirror; //0 = horizontal, 1 = vertical +} settings; + +uint2 prg_bank; +uint2 chr_bank; + +uint8 prg_read(unsigned addr) { + if(addr & 0x8000) return prgrom.read((prg_bank << 15) | (addr & 0x7fff)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr & 0x8000) { + prg_bank = (data & 0x30) >> 4; + chr_bank = (data & 0x03) >> 0; + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_read(addr & 0x07ff); + } + addr = (chr_bank * 0x2000) + (addr & 0x1fff); + return Board::chr_read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_write(addr & 0x07ff, data); + } + addr = (chr_bank * 0x2000) + (addr & 0x1fff); + Board::chr_write(addr, data); +} + +void power() { +} + +void reset() { + prg_bank = 0; + chr_bank = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + s.integer(prg_bank); + s.integer(chr_bank); +} + +NES_GxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { + settings.mirror = board["mirror"].value == "vertical" ? 1 : 0; +} + +}; diff --git a/nes/cartridge/board/nes-hkrom.cpp b/nes/cartridge/board/nes-hkrom.cpp new file mode 100755 index 00000000..8eb13a53 --- /dev/null +++ b/nes/cartridge/board/nes-hkrom.cpp @@ -0,0 +1,48 @@ +struct NES_HKROM : Board { + +MMC6 mmc6; + +void main() { + mmc6.main(); +} + +uint8 prg_read(unsigned addr) { + if((addr & 0xf000) == 0x7000) return mmc6.ram_read(addr); + if(addr & 0x8000) return prgrom.read(mmc6.prg_addr(addr)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xf000) == 0x7000) return mmc6.ram_write(addr, data); + if(addr & 0x8000) return mmc6.reg_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + mmc6.irq_test(addr); + if(addr & 0x2000) return ppu.ciram_read(mmc6.ciram_addr(addr)); + return Board::chr_read(mmc6.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + mmc6.irq_test(addr); + if(addr & 0x2000) return ppu.ciram_write(mmc6.ciram_addr(addr), data); + return Board::chr_write(mmc6.chr_addr(addr), data); +} + +void power() { + mmc6.power(); +} + +void reset() { + mmc6.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + mmc6.serialize(s); +} + +NES_HKROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc6(*this) { +} + +}; diff --git a/nes/cartridge/board/nes-nrom.cpp b/nes/cartridge/board/nes-nrom.cpp new file mode 100755 index 00000000..5cf60764 --- /dev/null +++ b/nes/cartridge/board/nes-nrom.cpp @@ -0,0 +1,43 @@ +//NES-NROM-128 +//NES-NROM-256 + +struct NES_NROM : Board { + +struct Settings { + bool mirror; //0 = horizontal, 1 = vertical +} settings; + +uint8 prg_read(unsigned addr) { + if(addr & 0x8000) return prgrom.read(addr); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_read(addr & 0x07ff); + } + if(chrram.size) return chrram.read(addr); + return chrrom.read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_write(addr & 0x07ff, data); + } + if(chrram.size) return chrram.write(addr, data); +} + +void serialize(serializer &s) { + Board::serialize(s); +} + +NES_NROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { + settings.mirror = board["mirror"].value == "vertical" ? 1 : 0; +} + +}; diff --git a/nes/cartridge/board/nes-pxrom.cpp b/nes/cartridge/board/nes-pxrom.cpp new file mode 100755 index 00000000..82b065ec --- /dev/null +++ b/nes/cartridge/board/nes-pxrom.cpp @@ -0,0 +1,97 @@ +//MMC2 + +struct NES_PxROM : Board { + +enum Revision : unsigned { + PEEOROM, + PNROM, +} revision; + +uint4 prg_bank; +uint5 chr_bank[2][2]; +bool mirror; +bool latch[2]; + +uint8 prg_read(unsigned addr) { + if(addr < 0x6000) return cpu.mdr(); + if(addr < 0x8000) return prgram.read(addr); + unsigned bank = 0; + switch((addr / 0x2000) & 3) { + case 0: bank = prg_bank; break; + case 1: bank = 0x0d; break; + case 2: bank = 0x0e; break; + case 3: bank = 0x0f; break; + } + return prgrom.read((bank * 0x2000) | (addr & 0x1fff)); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr < 0x6000) return; + if(addr < 0x8000) return prgram.write(addr, data); + + switch(addr & 0xf000) { + case 0xa000: prg_bank = data & 0x0f; break; + case 0xb000: chr_bank[0][0] = data & 0x1f; break; + case 0xc000: chr_bank[0][1] = data & 0x1f; break; + case 0xd000: chr_bank[1][0] = data & 0x1f; break; + case 0xe000: chr_bank[1][1] = data & 0x1f; break; + case 0xf000: mirror = data & 0x01; break; + } +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr)); + bool region = addr & 0x1000; + unsigned bank = chr_bank[region][latch[region]]; + if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0; + if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; + return Board::chr_read((bank * 0x1000) | (addr & 0x0fff)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data); + bool region = addr & 0x1000; + unsigned bank = chr_bank[region][latch[region]]; + if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0; + if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; + return Board::chr_write((bank * 0x1000) | (addr & 0x0fff), data); +} + +void power() { +} + +void reset() { + prg_bank = 0; + chr_bank[0][0] = 0; + chr_bank[0][1] = 0; + chr_bank[1][0] = 0; + chr_bank[1][1] = 0; + mirror = 0; + latch[0] = 0; + latch[1] = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + + s.integer(prg_bank); + s.integer(chr_bank[0][0]); + s.integer(chr_bank[0][1]); + s.integer(chr_bank[1][0]); + s.integer(chr_bank[1][1]); + s.integer(mirror); + s.array(latch); +} + +NES_PxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { + revision = Revision::PNROM; +} + +}; diff --git a/nes/cartridge/board/nes-sxrom.cpp b/nes/cartridge/board/nes-sxrom.cpp new file mode 100755 index 00000000..a6d933c3 --- /dev/null +++ b/nes/cartridge/board/nes-sxrom.cpp @@ -0,0 +1,101 @@ +struct NES_SxROM : Board { + +enum class Revision : unsigned { + SAROM, + SBROM, + SCROM, + SC1ROM, + SEROM, + SFROM, + SGROM, + SHROM, + SH1ROM, + SIROM, + SJROM, + SKROM, + SLROM, + SL1ROM, + SL2ROM, + SL3ROM, + SLRROM, + SMROM, + SNROM, + SOROM, + SUROM, + SXROM, +} revision; + +MMC1 mmc1; + +void main() { + return mmc1.main(); +} + +unsigned ram_addr(unsigned addr) { + unsigned bank = 0; + if(revision == Revision::SOROM) bank = (mmc1.chr_bank[0] & 0x08) >> 3; + if(revision == Revision::SUROM) bank = (mmc1.chr_bank[0] & 0x0c) >> 2; + if(revision == Revision::SXROM) bank = (mmc1.chr_bank[0] & 0x0c) >> 2; + return (bank << 13) | (addr & 0x1fff); +} + +uint8 prg_read(unsigned addr) { + if((addr & 0xe000) == 0x6000) { + if(revision == Revision::SNROM) { + if(mmc1.chr_bank[0] & 0x10) return cpu.mdr(); + } + if(mmc1.ram_disable) return 0x00; + return prgram.read(ram_addr(addr)); + } + + if(addr & 0x8000) { + addr = mmc1.prg_addr(addr); + if(revision == Revision::SXROM) { + addr |= ((mmc1.chr_bank[0] & 0x10) >> 4) << 18; + } + return prgrom.read(addr); + } + + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xe000) == 0x6000) { + if(revision == Revision::SNROM) { + if(mmc1.chr_bank[0] & 0x10) return; + } + if(mmc1.ram_disable) return; + return prgram.write(ram_addr(addr), data); + } + + if(addr & 0x8000) return mmc1.mmio_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(mmc1.ciram_addr(addr)); + return Board::chr_read(mmc1.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(mmc1.ciram_addr(addr), data); + return Board::chr_write(mmc1.chr_addr(addr), data); +} + +void power() { + mmc1.power(); +} + +void reset() { + mmc1.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + mmc1.serialize(s); +} + +NES_SxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc1(*this) { + revision = Revision::SXROM; +} + +}; diff --git a/nes/cartridge/board/nes-txrom.cpp b/nes/cartridge/board/nes-txrom.cpp new file mode 100755 index 00000000..24416f01 --- /dev/null +++ b/nes/cartridge/board/nes-txrom.cpp @@ -0,0 +1,67 @@ +struct NES_TxROM : Board { + +enum class Revision : unsigned { + TBROM, + TEROM, + TFROM, + TGROM, + TKROM, + TKSROM, + TLROM, + TL1ROM, + TL2ROM, + TLSROM, + TNROM, + TQROM, + TR1ROM, + TSROM, + TVROM, +} revision; + +MMC3 mmc3; + +void main() { + mmc3.main(); +} + +uint8 prg_read(unsigned addr) { + if((addr & 0xe000) == 0x6000) return mmc3.ram_read(addr); + if(addr & 0x8000) return prgrom.read(mmc3.prg_addr(addr)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xe000) == 0x6000) return mmc3.ram_write(addr, data); + if(addr & 0x8000) return mmc3.reg_write(addr, data); +} + +uint8 chr_read(unsigned addr) { + mmc3.irq_test(addr); + if(addr & 0x2000) return ppu.ciram_read(mmc3.ciram_addr(addr)); + return Board::chr_read(mmc3.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + mmc3.irq_test(addr); + if(addr & 0x2000) return ppu.ciram_write(mmc3.ciram_addr(addr), data); + return Board::chr_write(mmc3.chr_addr(addr), data); +} + +void power() { + mmc3.power(); +} + +void reset() { + mmc3.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + mmc3.serialize(s); +} + +NES_TxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc3(*this) { + revision = Revision::TLROM; +} + +}; diff --git a/nes/cartridge/board/nes-uxrom.cpp b/nes/cartridge/board/nes-uxrom.cpp new file mode 100755 index 00000000..4ad0a3d5 --- /dev/null +++ b/nes/cartridge/board/nes-uxrom.cpp @@ -0,0 +1,55 @@ +//NES-UNROM +//NES-UOROM + +struct NES_UxROM : Board { + +struct Settings { + bool mirror; //0 = horizontal, 1 = vertical +} settings; + +uint4 prg_bank; + +uint8 prg_read(unsigned addr) { + if((addr & 0xc000) == 0x8000) return prgrom.read((prg_bank << 14) | (addr & 0x3fff)); + if((addr & 0xc000) == 0xc000) return prgrom.read(( 0x0f << 14) | (addr & 0x3fff)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr & 0x8000) prg_bank = data & 0x0f; +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_read(addr); + } + return Board::chr_read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) { + if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); + return ppu.ciram_write(addr, data); + } + return Board::chr_write(addr, data); +} + +void power() { +} + +void reset() { + prg_bank = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + + s.integer(prg_bank); +} + +NES_UxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { + settings.mirror = board["mirror"].value == "vertical" ? 1 : 0; +} + +}; diff --git a/nes/cartridge/board/sunsoft-5b.cpp b/nes/cartridge/board/sunsoft-5b.cpp new file mode 100755 index 00000000..6732271a --- /dev/null +++ b/nes/cartridge/board/sunsoft-5b.cpp @@ -0,0 +1,226 @@ +//SUNSOFT-5B + +struct Sunsoft5B : Board { + +uint4 mmu_port; +uint4 apu_port; + +uint8 prg_bank[4]; +uint8 chr_bank[8]; +uint2 mirror; +bool irq_enable; +bool irq_counter_enable; +uint16 irq_counter; + +int16 dac[16]; + +struct Pulse { + bool disable; + uint12 frequency; + uint4 volume; + + uint16 counter; //12-bit countdown + 4-bit phase + uint1 duty; + uint4 output; + + void clock() { + if(--counter == 0) { + counter = frequency << 4; + duty ^= 1; + } + output = duty ? volume : (uint4)0; + if(disable) output = 0; + } + + void reset() { + disable = 1; + frequency = 1; + volume = 0; + + counter = 0; + duty = 0; + output = 0; + } + + void serialize(serializer &s) { + s.integer(disable); + s.integer(frequency); + s.integer(volume); + + s.integer(counter); + s.integer(duty); + s.integer(output); + } +} pulse[3]; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_counter_enable) { + if(--irq_counter == 0xffff) { + cpu.set_irq_line(irq_enable); + } + } + + pulse[0].clock(); + pulse[1].clock(); + pulse[2].clock(); + int16 output = dac[pulse[0].output] + dac[pulse[1].output] + dac[pulse[2].output]; + apu.set_sample(-output); + + tick(); + } +} + +uint8 prg_read(unsigned addr) { + if(addr < 0x6000) return cpu.mdr(); + + uint8 bank = 0x3f; //((addr & 0xe000) == 0xe000 + if((addr & 0xe000) == 0x6000) bank = prg_bank[0]; + if((addr & 0xe000) == 0x8000) bank = prg_bank[1]; + if((addr & 0xe000) == 0xa000) bank = prg_bank[2]; + if((addr & 0xe000) == 0xc000) bank = prg_bank[3]; + + bool ram_enable = bank & 0x80; + bool ram_select = bank & 0x40; + bank &= 0x3f; + + if(ram_select) { + if(ram_enable == false) return cpu.mdr(); + return prgram.data[addr & 0x1fff]; + } + + addr = (bank << 13) | (addr & 0x1fff); + return prgrom.read(addr); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xe000) == 0x6000) { + prgram.data[addr & 0x1fff] = data; + } + + if(addr == 0x8000) { + mmu_port = data & 0x0f; + } + + if(addr == 0xa000) { + switch(mmu_port) { + case 0: chr_bank[0] = data; break; + case 1: chr_bank[1] = data; break; + case 2: chr_bank[2] = data; break; + case 3: chr_bank[3] = data; break; + case 4: chr_bank[4] = data; break; + case 5: chr_bank[5] = data; break; + case 6: chr_bank[6] = data; break; + case 7: chr_bank[7] = data; break; + case 8: prg_bank[0] = data; break; + case 9: prg_bank[1] = data; break; + case 10: prg_bank[2] = data; break; + case 11: prg_bank[3] = data; break; + case 12: mirror = data & 3; break; + case 13: + irq_enable = data & 0x80; + irq_counter_enable = data & 0x01; + if(irq_enable == 0) cpu.set_irq_line(0); + break; + case 14: irq_counter = (irq_counter & 0xff00) | (data << 0); break; + case 15: irq_counter = (irq_counter & 0x00ff) | (data << 8); break; + } + } + + if(addr == 0xc000) { + apu_port = data & 0x0f; + } + + if(addr == 0xe000) { + switch(apu_port) { + case 0: pulse[0].frequency = (pulse[0].frequency & 0xff00) | (data << 0); break; + case 1: pulse[0].frequency = (pulse[0].frequency & 0x00ff) | (data << 8); break; + case 2: pulse[1].frequency = (pulse[1].frequency & 0xff00) | (data << 0); break; + case 3: pulse[1].frequency = (pulse[1].frequency & 0x00ff) | (data << 8); break; + case 4: pulse[2].frequency = (pulse[2].frequency & 0xff00) | (data << 0); break; + case 5: pulse[2].frequency = (pulse[2].frequency & 0x00ff) | (data << 8); break; + case 7: + pulse[0].disable = data & 0x01; + pulse[1].disable = data & 0x02; + pulse[2].disable = data & 0x04; + break; + case 8: pulse[0].volume = data & 0x0f; break; + case 9: pulse[1].volume = data & 0x0f; break; + case 10: pulse[2].volume = data & 0x0f; break; + } + } +} + +unsigned chr_addr(unsigned addr) { + uint8 bank = (addr >> 10) & 7; + return (chr_bank[bank] << 10) | (addr & 0x03ff); +} + +unsigned ciram_addr(unsigned addr) { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal + case 2: return 0x0000 | (addr & 0x03ff); //first + case 3: return 0x0400 | (addr & 0x03ff); //second + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr)); + return Board::chr_read(chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data); + return Board::chr_write(chr_addr(addr), data); +} + +void power() { + for(signed n = 0; n < 16; n++) { + double volume = 1.0 / pow(2, 1.0 / 2 * (15 - n)); + dac[n] = volume * 8192.0; + } +} + +void reset() { + mmu_port = 0; + apu_port = 0; + + for(auto &n : prg_bank) n = 0; + for(auto &n : chr_bank) n = 0; + mirror = 0; + irq_enable = 0; + irq_counter_enable = 0; + irq_counter = 0; + + pulse[0].reset(); + pulse[1].reset(); + pulse[2].reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + + s.integer(mmu_port); + s.integer(apu_port); + + s.array(prg_bank); + s.array(chr_bank); + s.integer(mirror); + s.integer(irq_enable); + s.integer(irq_counter_enable); + s.integer(irq_counter); + + pulse[0].serialize(s); + pulse[1].serialize(s); + pulse[2].serialize(s); +} + +Sunsoft5B(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { +} + +}; diff --git a/nes/cartridge/cartridge.cpp b/nes/cartridge/cartridge.cpp new file mode 100755 index 00000000..a88c4950 --- /dev/null +++ b/nes/cartridge/cartridge.cpp @@ -0,0 +1,85 @@ +#include + +namespace NES { + +#include "ines.cpp" +#include "chip/chip.cpp" +#include "board/board.cpp" +Cartridge cartridge; + +void Cartridge::Main() { + cartridge.main(); +} + +void Cartridge::main() { + board->main(); +} + +void Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { + if((size & 0xff) == 0) { + sha256 = nall::sha256(data, size); + board = Board::load(markup, data, size); + } else { + //unsigned crc32 = crc32_calculate(data + 16, size - 16); + //print(hex<8>(crc32), "\n"); + sha256 = nall::sha256(data + 16, size - 16); + board = Board::load(markup != "" ? markup : iNES(data, size), data + 16, size - 16); + } + if(board == nullptr) return; + + system.load(); + loaded = true; +} + +void Cartridge::unload() { + if(loaded == false) return; + loaded = false; +} + +unsigned Cartridge::ram_size() { + return board->memory().size; +} + +uint8* Cartridge::ram_data() { + return board->memory().data; +} + +void Cartridge::power() { + board->power(); +} + +void Cartridge::reset() { + create(Cartridge::Main, 21477272); + board->reset(); +} + +Cartridge::Cartridge() { + loaded = false; +} + +uint8 Cartridge::prg_read(unsigned addr) { + return board->prg_read(addr); +} + +void Cartridge::prg_write(unsigned addr, uint8 data) { + return board->prg_write(addr, data); +} + +uint8 Cartridge::chr_read(unsigned addr) { + return board->chr_read(addr); +} + +void Cartridge::chr_write(unsigned addr, uint8 data) { + return board->chr_write(addr, data); +} + +void Cartridge::scanline(unsigned y) { + return board->scanline(y); +} + +void Cartridge::serialize(serializer &s) { + Processor::serialize(s); + return board->serialize(s); +} + +} diff --git a/nes/cartridge/cartridge.hpp b/nes/cartridge/cartridge.hpp new file mode 100755 index 00000000..9b1f1db1 --- /dev/null +++ b/nes/cartridge/cartridge.hpp @@ -0,0 +1,37 @@ +#include "chip/chip.hpp" +#include "board/board.hpp" + +struct Cartridge : Processor, property { + static void Main(); + void main(); + + void load(const string &markup, const uint8_t *data, unsigned size); + void unload(); + + unsigned ram_size(); + uint8* ram_data(); + + void power(); + void reset(); + + readonly loaded; + readonly sha256; + + void serialize(serializer&); + Cartridge(); + +//privileged: + Board *board; + + uint8 prg_read(unsigned addr); + void prg_write(unsigned addr, uint8 data); + + uint8 chr_read(unsigned addr); + void chr_write(unsigned addr, uint8 data); + + //scanline() is for debugging purposes only: + //boards must detect scanline edges on their own + void scanline(unsigned y); +}; + +extern Cartridge cartridge; diff --git a/nes/cartridge/chip/chip.cpp b/nes/cartridge/chip/chip.cpp new file mode 100755 index 00000000..1d0f9fb6 --- /dev/null +++ b/nes/cartridge/chip/chip.cpp @@ -0,0 +1,17 @@ +#include "mmc1.cpp" +#include "mmc3.cpp" +#include "mmc5.cpp" +#include "mmc6.cpp" +#include "vrc1.cpp" +#include "vrc2.cpp" +#include "vrc3.cpp" +#include "vrc4.cpp" +#include "vrc6.cpp" +#include "vrc7.cpp" + +void Chip::tick() { + board.tick(); +} + +Chip::Chip(Board &board) : board(board) { +} diff --git a/nes/cartridge/chip/chip.hpp b/nes/cartridge/chip/chip.hpp new file mode 100755 index 00000000..8753c66b --- /dev/null +++ b/nes/cartridge/chip/chip.hpp @@ -0,0 +1,7 @@ +struct Board; + +struct Chip { + Board &board; + void tick(); + Chip(Board &board); +}; diff --git a/nes/cartridge/chip/mmc1.cpp b/nes/cartridge/chip/mmc1.cpp new file mode 100755 index 00000000..15dc3097 --- /dev/null +++ b/nes/cartridge/chip/mmc1.cpp @@ -0,0 +1,136 @@ +struct MMC1 : Chip { + +enum class Revision : unsigned { + MMC1, + MMC1A, + MMC1B1, + MMC1B2, + MMC1B3, + MMC1C, +} revision; + +unsigned writedelay; +unsigned shiftaddr; +unsigned shiftdata; + +bool chr_mode; +bool prg_size; //0 = 32K, 1 = 16K +bool prg_mode; +uint2 mirror; //0 = first, 1 = second, 2 = vertical, 3 = horizontal +uint5 chr_bank[2]; +bool ram_disable; +uint4 prg_bank; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(writedelay) writedelay--; + tick(); + } +} + +unsigned prg_addr(unsigned addr) { + bool region = addr & 0x4000; + unsigned bank = (prg_bank & ~1) + region; + + if(prg_size) { + bank = (region == 0 ? 0x0 : 0xf); + if(region != prg_mode) bank = prg_bank; + } + + return (bank << 14) | (addr & 0x3fff); +} + +unsigned chr_addr(unsigned addr) { + bool region = addr & 0x1000; + unsigned bank = chr_bank[region]; + if(chr_mode == 0) bank = (chr_bank[0] & ~1) | region; + return (bank << 12) | (addr & 0x0fff); +} + +unsigned ciram_addr(unsigned addr) { + switch(mirror) { + case 0: return 0x0000 | (addr & 0x03ff); + case 1: return 0x0400 | (addr & 0x03ff); + case 2: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); + case 3: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); + } +} + +void mmio_write(unsigned addr, uint8 data) { + if(writedelay) return; + writedelay = 2; + + if(data & 0x80) { + shiftaddr = 0; + prg_size = 1; + prg_mode = 1; + } else { + shiftdata = ((data & 1) << 4) | (shiftdata >> 1); + if(++shiftaddr == 5) { + shiftaddr = 0; + switch((addr >> 13) & 3) { + case 0: + chr_mode = (shiftdata & 0x10); + prg_size = (shiftdata & 0x08); + prg_mode = (shiftdata & 0x04); + mirror = (shiftdata & 0x03); + break; + + case 1: + chr_bank[0] = (shiftdata & 0x1f); + break; + + case 2: + chr_bank[1] = (shiftdata & 0x1f); + break; + + case 3: + ram_disable = (shiftdata & 0x10); + prg_bank = (shiftdata & 0x0f); + break; + } + } + } +} + +void power() { +} + +void reset() { + writedelay = 0; + shiftaddr = 0; + shiftdata = 0; + + chr_mode = 0; + prg_size = 1; + prg_mode = 1; + mirror = 0; + chr_bank[0] = 0; + chr_bank[1] = 1; + ram_disable = 0; + prg_bank = 0; +} + +void serialize(serializer &s) { + s.integer(writedelay); + s.integer(shiftaddr); + s.integer(shiftdata); + + s.integer(chr_mode); + s.integer(prg_size); + s.integer(prg_mode); + s.integer(mirror); + s.array(chr_bank); + s.integer(ram_disable); + s.integer(prg_bank); +} + +MMC1(Board &board) : Chip(board) { + revision = Revision::MMC1B2; +} + +}; diff --git a/nes/cartridge/chip/mmc3.cpp b/nes/cartridge/chip/mmc3.cpp new file mode 100755 index 00000000..d4203a0a --- /dev/null +++ b/nes/cartridge/chip/mmc3.cpp @@ -0,0 +1,189 @@ +struct MMC3 : Chip { + +bool chr_mode; +bool prg_mode; +uint3 bank_select; +uint8 prg_bank[2]; +uint8 chr_bank[6]; +bool mirror; +bool ram_enable; +bool ram_write_protect; +uint8 irq_latch; +uint8 irq_counter; +bool irq_enable; +unsigned irq_delay; +bool irq_line; + +uint16 chr_abus; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_delay) irq_delay--; + cpu.set_irq_line(irq_line); + tick(); + } +} + +void irq_test(unsigned addr) { + if(!(chr_abus & 0x1000) && (addr & 0x1000)) { + if(irq_delay == 0) { + if(irq_counter == 0) { + irq_counter = irq_latch; + } else if(--irq_counter == 0) { + if(irq_enable) irq_line = 1; + } + } + irq_delay = 6; + } + chr_abus = addr; +} + +unsigned prg_addr(unsigned addr) const { + switch((addr >> 13) & 3) { + case 0: + if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff); + return (prg_bank[0] << 13) | (addr & 0x1fff); + case 1: + return (prg_bank[1] << 13) | (addr & 0x1fff); + case 2: + if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff); + return (prg_bank[0] << 13) | (addr & 0x1fff); + case 3: + return (0x3f << 13) | (addr & 0x1fff); + } +} + +unsigned chr_addr(unsigned addr) const { + if(chr_mode == 0) { + if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff); + if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff); + if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff); + if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff); + if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff); + if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff); + } else { + if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff); + if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff); + if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff); + if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff); + if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff); + if(addr <= 0x1fff) return (chr_bank[1] << 10) | (addr & 0x07ff); + } +} + +unsigned ciram_addr(unsigned addr) const { + if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff); + if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff); +} + +uint8 ram_read(unsigned addr) { + if(ram_enable) return board.prgram.data[addr & 0x1fff]; + return 0x00; +} + +void ram_write(unsigned addr, uint8 data) { + if(ram_enable && !ram_write_protect) board.prgram.data[addr & 0x1fff] = data; +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr & 0xe001) { + case 0x8000: + chr_mode = data & 0x80; + prg_mode = data & 0x40; + bank_select = data & 0x07; + break; + + case 0x8001: + switch(bank_select) { + case 0: chr_bank[0] = data & ~1; break; + case 1: chr_bank[1] = data & ~1; break; + case 2: chr_bank[2] = data; break; + case 3: chr_bank[3] = data; break; + case 4: chr_bank[4] = data; break; + case 5: chr_bank[5] = data; break; + case 6: prg_bank[0] = data & 0x3f; break; + case 7: prg_bank[1] = data & 0x3f; break; + } + break; + + case 0xa000: + mirror = data & 0x01; + break; + + case 0xa001: + ram_enable = data & 0x80; + ram_write_protect = data & 0x40; + break; + + case 0xc000: + irq_latch = data; + break; + + case 0xc001: + irq_counter = 0; + break; + + case 0xe000: + irq_enable = false; + irq_line = 0; + break; + + case 0xe001: + irq_enable = true; + break; + } +} + +void power() { +} + +void reset() { + chr_mode = 0; + prg_mode = 0; + bank_select = 0; + prg_bank[0] = 0; + prg_bank[1] = 0; + chr_bank[0] = 0; + chr_bank[1] = 0; + chr_bank[2] = 0; + chr_bank[3] = 0; + chr_bank[4] = 0; + chr_bank[5] = 0; + mirror = 0; + ram_enable = 1; + ram_write_protect = 0; + irq_latch = 0; + irq_counter = 0; + irq_enable = false; + irq_delay = 0; + irq_line = 0; + + chr_abus = 0; +} + +void serialize(serializer &s) { + s.integer(chr_mode); + s.integer(prg_mode); + s.integer(bank_select); + s.array(prg_bank); + s.array(chr_bank); + s.integer(mirror); + s.integer(ram_enable); + s.integer(ram_write_protect); + s.integer(irq_latch); + s.integer(irq_counter); + s.integer(irq_enable); + s.integer(irq_delay); + s.integer(irq_line); + + s.integer(chr_abus); +} + +MMC3(Board &board) : Chip(board) { +} + +}; diff --git a/nes/cartridge/chip/mmc5.cpp b/nes/cartridge/chip/mmc5.cpp new file mode 100755 index 00000000..6f62e4f9 --- /dev/null +++ b/nes/cartridge/chip/mmc5.cpp @@ -0,0 +1,497 @@ +struct MMC5 : Chip { + +enum class Revision : unsigned { + MMC5, + MMC5B, +} revision; + +uint8 exram[1024]; + +//programmable registers + +uint2 prg_mode; //$5100 +uint2 chr_mode; //$5101 + +uint2 prgram_write_protect[2]; //$5102,$5103 + +uint2 exram_mode; //$5104 +uint2 nametable_mode[4]; //$5105 +uint8 fillmode_tile; //$5106 +uint8 fillmode_color; //$5107 + +bool ram_select; //$5113 +uint2 ram_bank; //$5113 +uint8 prg_bank[4]; //$5114-5117 +uint10 chr_sprite_bank[8]; //$5120-5127 +uint10 chr_bg_bank[4]; //$5128-512b +uint2 chr_bank_hi; //$5130 + +bool vs_enable; //$5200 +bool vs_side; //$5200 +uint5 vs_tile; //$5200 +uint8 vs_scroll; //$5201 +uint8 vs_bank; //$5202 + +uint8 irq_line; //$5203 +bool irq_enable; //$5204 + +uint8 multiplicand; //$5205 +uint8 multiplier; //$5206 + +//status registers + +unsigned cpu_cycle_counter; +unsigned irq_counter; +bool irq_pending; +bool in_frame; + +unsigned vcounter; +unsigned hcounter; +uint16 chr_access[4]; +bool chr_active; +bool sprite_8x16; + +uint8 exbank; +uint8 exattr; + +bool vs_fetch; +uint8 vs_vpos; +uint8 vs_hpos; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + //scanline() resets this; if no scanlines detected, enter video blanking period + if(++cpu_cycle_counter >= 200) blank(); //113-114 normal; ~2500 across Vblank period + + cpu.set_irq_line(irq_enable && irq_pending); + tick(); + } +} + +void scanline(unsigned y) { +//used for testing only, to verify MMC5 scanline detection is accurate: +//if(y != vcounter && y <= 240) print(y, " vs ", vcounter, "\n"); +} + +uint8 prg_access(bool write, unsigned addr, uint8 data = 0x00) { + unsigned bank; + + if((addr & 0xe000) == 0x6000) { + bank = (ram_select << 2) | ram_bank; + addr &= 0x1fff; + } else if(prg_mode == 0) { + bank = prg_bank[3] & ~3; + addr &= 0x7fff; + } else if(prg_mode == 1) { + if((addr & 0xc000) == 0x8000) bank = (prg_bank[1] & ~1); + if((addr & 0xe000) == 0xc000) bank = (prg_bank[3] & ~1); + addr &= 0x3fff; + } else if(prg_mode == 2) { + if((addr & 0xe000) == 0x8000) bank = (prg_bank[1] & ~1) | 0; + if((addr & 0xe000) == 0xa000) bank = (prg_bank[1] & ~1) | 1; + if((addr & 0xe000) == 0xc000) bank = (prg_bank[2]); + if((addr & 0xe000) == 0xe000) bank = (prg_bank[3]); + addr &= 0x1fff; + } else if(prg_mode == 3) { + if((addr & 0xe000) == 0x8000) bank = prg_bank[0]; + if((addr & 0xe000) == 0xa000) bank = prg_bank[1]; + if((addr & 0xe000) == 0xc000) bank = prg_bank[2]; + if((addr & 0xe000) == 0xe000) bank = prg_bank[3]; + addr &= 0x1fff; + } + + bool rom = bank & 0x80; + bank &= 0x7f; + + if(write == false) { + if(rom) { + return board.prgrom.read((bank << 13) | addr); + } else { + return board.prgram.read((bank << 13) | addr); + } + } else { + if(rom) { + board.prgrom.write((bank << 13) | addr, data); + } else { + if(prgram_write_protect[0] == 2 && prgram_write_protect[1] == 1) { + board.prgram.write((bank << 13) | addr, data); + } + } + return 0x00; + } +} + +uint8 prg_read(unsigned addr) { + if((addr & 0xfc00) == 0x5c00) { + if(exram_mode >= 2) return exram[addr & 0x03ff]; + return cpu.mdr(); + } + + if(addr >= 0x6000) { + return prg_access(0, addr); + } + + switch(addr) { + case 0x5204: { + uint8 result = (irq_pending << 7) | (in_frame << 6); + irq_pending = false; + return result; + } + case 0x5205: return (multiplier * multiplicand) >> 0; + case 0x5206: return (multiplier * multiplicand) >> 8; + } +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xfc00) == 0x5c00) { + //writes 0x00 *during* Vblank (not during screen rendering ...) + if(exram_mode == 0 || exram_mode == 1) exram[addr & 0x03ff] = in_frame ? data : 0x00; + if(exram_mode == 2) exram[addr & 0x03ff] = data; + return; + } + + if(addr >= 0x6000) { + prg_access(1, addr, data); + return; + } + + switch(addr) { + case 0x2000: + sprite_8x16 = data & 0x20; + break; + + case 0x2001: + //if BG+sprites are disabled; enter video blanking period + if((data & 0x18) == 0) blank(); + break; + + case 0x5100: prg_mode = data & 3; break; + case 0x5101: chr_mode = data & 3; break; + + case 0x5102: prgram_write_protect[0] = data & 3; break; + case 0x5103: prgram_write_protect[1] = data & 3; break; + + case 0x5104: + exram_mode = data & 3; + break; + + case 0x5105: + nametable_mode[0] = (data & 0x03) >> 0; + nametable_mode[1] = (data & 0x0c) >> 2; + nametable_mode[2] = (data & 0x30) >> 4; + nametable_mode[3] = (data & 0xc0) >> 6; + break; + + case 0x5106: + fillmode_tile = data; + break; + + case 0x5107: + fillmode_color = data & 3; + fillmode_color |= fillmode_color << 2; + fillmode_color |= fillmode_color << 4; + break; + + case 0x5113: + ram_select = data & 0x04; + ram_bank = data & 0x03; + break; + + case 0x5114: prg_bank[0] = data; break; + case 0x5115: prg_bank[1] = data; break; + case 0x5116: prg_bank[2] = data; break; + case 0x5117: prg_bank[3] = data | 0x80; break; + + case 0x5120: chr_sprite_bank[0] = (chr_bank_hi << 8) | data; chr_active = 0; break; + case 0x5121: chr_sprite_bank[1] = (chr_bank_hi << 8) | data; chr_active = 0; break; + case 0x5122: chr_sprite_bank[2] = (chr_bank_hi << 8) | data; chr_active = 0; break; + case 0x5123: chr_sprite_bank[3] = (chr_bank_hi << 8) | data; chr_active = 0; break; + case 0x5124: chr_sprite_bank[4] = (chr_bank_hi << 8) | data; chr_active = 0; break; + case 0x5125: chr_sprite_bank[5] = (chr_bank_hi << 8) | data; chr_active = 0; break; + case 0x5126: chr_sprite_bank[6] = (chr_bank_hi << 8) | data; chr_active = 0; break; + case 0x5127: chr_sprite_bank[7] = (chr_bank_hi << 8) | data; chr_active = 0; break; + + case 0x5128: chr_bg_bank[0] = (chr_bank_hi << 8) | data; chr_active = 1; break; + case 0x5129: chr_bg_bank[1] = (chr_bank_hi << 8) | data; chr_active = 1; break; + case 0x512a: chr_bg_bank[2] = (chr_bank_hi << 8) | data; chr_active = 1; break; + case 0x512b: chr_bg_bank[3] = (chr_bank_hi << 8) | data; chr_active = 1; break; + + case 0x5130: + chr_bank_hi = data & 3; + break; + + case 0x5200: + vs_enable = data & 0x80; + vs_side = data & 0x40; + vs_tile = data & 0x1f; + break; + + case 0x5201: + vs_scroll = data; + break; + + case 0x5202: + vs_bank = data; + break; + + case 0x5203: + irq_line = data; + break; + + case 0x5204: + irq_enable = data & 0x80; + break; + + case 0x5205: + multiplicand = data; + break; + + case 0x5206: + multiplier = data; + break; + } +} + +unsigned chr_sprite_addr(unsigned addr) { + if(chr_mode == 0) { + auto bank = chr_sprite_bank[7]; + return (bank * 0x2000) + (addr & 0x1fff); + } + + if(chr_mode == 1) { + auto bank = chr_sprite_bank[(addr / 0x1000) * 4 + 3]; + return (bank * 0x1000) + (addr & 0x0fff); + } + + if(chr_mode == 2) { + auto bank = chr_sprite_bank[(addr / 0x0800) * 2 + 1]; + return (bank * 0x0800) + (addr & 0x07ff); + } + + if(chr_mode == 3) { + auto bank = chr_sprite_bank[(addr / 0x0400)]; + return (bank * 0x0400) + (addr & 0x03ff); + } +} + +unsigned chr_bg_addr(unsigned addr) { + addr &= 0x0fff; + + if(chr_mode == 0) { + auto bank = chr_bg_bank[3]; + return (bank * 0x2000) + (addr & 0x0fff); + } + + if(chr_mode == 1) { + auto bank = chr_bg_bank[3]; + return (bank * 0x1000) + (addr & 0x0fff); + } + + if(chr_mode == 2) { + auto bank = chr_bg_bank[(addr / 0x0800) * 2 + 1]; + return (bank * 0x0800) + (addr & 0x07ff); + } + + if(chr_mode == 3) { + auto bank = chr_bg_bank[(addr / 0x0400)]; + return (bank * 0x0400) + (addr & 0x03ff); + } +} + +unsigned chr_vs_addr(unsigned addr) { + return (vs_bank * 0x1000) + (addr & 0x0ff8) + (vs_vpos & 7); +} + +void blank() { + in_frame = false; +} + +void scanline() { + hcounter = 0; + + if(in_frame == false) { + in_frame = true; + irq_pending = false; + vcounter = 0; + } else { + if(vcounter == irq_line) irq_pending = true; + vcounter++; + } + + cpu_cycle_counter = 0; +} + +uint8 ciram_read(unsigned addr) { + if(vs_fetch && (hcounter & 2) == 0) return exram[vs_vpos / 8 * 32 + vs_hpos / 8]; + if(vs_fetch && (hcounter & 2) != 0) return exram[vs_vpos / 32 * 8 + vs_hpos / 32 + 0x03c0]; + + switch(nametable_mode[(addr >> 10) & 3]) { + case 0: return ppu.ciram_read(0x0000 | (addr & 0x03ff)); + case 1: return ppu.ciram_read(0x0400 | (addr & 0x03ff)); + case 2: return exram_mode < 2 ? exram[addr & 0x03ff] : 0x00; + case 3: return (hcounter & 2) == 0 ? fillmode_tile : fillmode_color; + } +} + +uint8 chr_read(unsigned addr) { + chr_access[0] = chr_access[1]; + chr_access[1] = chr_access[2]; + chr_access[2] = chr_access[3]; + chr_access[3] = addr; + + //detect two unused nametable fetches at end of each scanline + if((chr_access[0] & 0x2000) == 0 + && (chr_access[1] & 0x2000) + && (chr_access[2] & 0x2000) + && (chr_access[3] & 0x2000)) scanline(); + + if(in_frame == false) { + vs_fetch = false; + if(addr & 0x2000) return ciram_read(addr); + return board.chrrom.read(chr_active ? chr_bg_addr(addr) : chr_sprite_addr(addr)); + } + + bool bg_fetch = (hcounter < 256 || hcounter >= 320); + uint8 result = 0x00; + + if((hcounter & 7) == 0) { + vs_hpos = hcounter >= 320 ? hcounter - 320 : hcounter + 16; + vs_vpos = vcounter + vs_scroll; + vs_fetch = vs_enable && bg_fetch && exram_mode < 2 + && (vs_side ? vs_hpos / 8 >= vs_tile : vs_hpos / 8 < vs_tile); + if(vs_vpos >= 240) vs_vpos -= 240; + + result = ciram_read(addr); + + exbank = (chr_bank_hi << 6) | (exram[addr & 0x03ff] & 0x3f); + exattr = exram[addr & 0x03ff] >> 6; + exattr |= exattr << 2; + exattr |= exattr << 4; + } else if((hcounter & 7) == 2) { + result = ciram_read(addr); + if(bg_fetch && exram_mode == 1) result = exattr; + } else { + if(vs_fetch) result = board.chrrom.read(chr_vs_addr(addr)); + else if(sprite_8x16 ? bg_fetch : chr_active) result = board.chrrom.read(chr_bg_addr(addr)); + else result = board.chrrom.read(chr_sprite_addr(addr)); + if(bg_fetch && exram_mode == 1) result = board.chrrom.read(exbank * 0x1000 + (addr & 0x0fff)); + } + + hcounter += 2; + return result; +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) { + switch(nametable_mode[(addr >> 10) & 3]) { + case 0: return ppu.ciram_write(0x0000 | (addr & 0x03ff), data); + case 1: return ppu.ciram_write(0x0400 | (addr & 0x03ff), data); + case 2: exram[addr & 0x03ff] = data; break; + } + } +} + +void power() { +} + +void reset() { + for(auto &n : exram) n = 0xff; + + prg_mode = 3; + chr_mode = 0; + for(auto &n : prgram_write_protect) n = 0; + exram_mode = 0; + for(auto &n : nametable_mode) n = 0; + fillmode_tile = 0; + fillmode_color = 0; + ram_select = 0; + ram_bank = 0; + prg_bank[0] = 0x00; + prg_bank[1] = 0x00; + prg_bank[2] = 0x00; + prg_bank[3] = 0xff; + for(auto &n : chr_sprite_bank) n = 0; + for(auto &n : chr_bg_bank) n = 0; + chr_bank_hi = 0; + vs_enable = 0; + vs_side = 0; + vs_tile = 0; + vs_scroll = 0; + vs_bank = 0; + irq_line = 0; + irq_enable = 0; + multiplicand = 0; + multiplier = 0; + + cpu_cycle_counter = 0; + irq_counter = 0; + irq_pending = 0; + in_frame = 0; + vcounter = 0; + hcounter = 0; + for(auto &n : chr_access) n = 0; + chr_active = 0; + sprite_8x16 = 0; + + exbank = 0; + exattr = 0; + + vs_fetch = 0; + vs_vpos = 0; + vs_hpos = 0; +} + +void serialize(serializer &s) { + s.array(exram); + + s.integer(prg_mode); + s.integer(chr_mode); + for(auto &n : prgram_write_protect) s.integer(n); + s.integer(exram_mode); + for(auto &n : nametable_mode) s.integer(n); + s.integer(fillmode_tile); + s.integer(fillmode_color); + s.integer(ram_select); + s.integer(ram_bank); + for(auto &n : prg_bank) s.integer(n); + for(auto &n : chr_sprite_bank) s.integer(n); + for(auto &n : chr_bg_bank) s.integer(n); + s.integer(chr_bank_hi); + s.integer(vs_enable); + s.integer(vs_side); + s.integer(vs_tile); + s.integer(vs_scroll); + s.integer(vs_bank); + s.integer(irq_line); + s.integer(irq_enable); + s.integer(multiplicand); + s.integer(multiplier); + + s.integer(cpu_cycle_counter); + s.integer(irq_counter); + s.integer(irq_pending); + s.integer(in_frame); + + s.integer(vcounter); + s.integer(hcounter); + for(auto &n : chr_access) s.integer(n); + s.integer(chr_active); + s.integer(sprite_8x16); + + s.integer(exbank); + s.integer(exattr); + + s.integer(vs_fetch); + s.integer(vs_vpos); + s.integer(vs_hpos); +} + +MMC5(Board &board) : Chip(board) { + revision = Revision::MMC5; +} + +}; diff --git a/nes/cartridge/chip/mmc6.cpp b/nes/cartridge/chip/mmc6.cpp new file mode 100755 index 00000000..ce43d0dd --- /dev/null +++ b/nes/cartridge/chip/mmc6.cpp @@ -0,0 +1,200 @@ +struct MMC6 : Chip { + +bool chr_mode; +bool prg_mode; +bool ram_enable; +uint3 bank_select; +uint8 prg_bank[2]; +uint8 chr_bank[6]; +bool mirror; +bool ram_readable[2]; +bool ram_writable[2]; +uint8 irq_latch; +uint8 irq_counter; +bool irq_enable; +unsigned irq_delay; +bool irq_line; + +uint16 chr_abus; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_delay) irq_delay--; + cpu.set_irq_line(irq_line); + tick(); + } +} + +void irq_test(unsigned addr) { + if(!(chr_abus & 0x1000) && (addr & 0x1000)) { + if(irq_delay == 0) { + if(irq_counter == 0) { + irq_counter = irq_latch; + } else if(--irq_counter == 0) { + if(irq_enable) irq_line = 1; + } + } + irq_delay = 6; + } + chr_abus = addr; +} + +unsigned prg_addr(unsigned addr) const { + switch((addr >> 13) & 3) { + case 0: + if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff); + return (prg_bank[0] << 13) | (addr & 0x1fff); + case 1: + return (prg_bank[1] << 13) | (addr & 0x1fff); + case 2: + if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff); + return (prg_bank[0] << 13) | (addr & 0x1fff); + case 3: + return (0x3f << 13) | (addr & 0x1fff); + } +} + +unsigned chr_addr(unsigned addr) const { + if(chr_mode == 0) { + if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff); + if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff); + if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff); + if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff); + if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff); + if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff); + } else { + if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff); + if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff); + if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff); + if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff); + if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff); + if(addr <= 0x1fff) return (chr_bank[1] << 10) | (addr & 0x07ff); + } +} + +unsigned ciram_addr(unsigned addr) const { + if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff); + if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff); +} + +uint8 ram_read(unsigned addr) { + if(ram_enable == false) return cpu.mdr(); + if(ram_readable[0] == false && ram_readable[1] == false) return cpu.mdr(); + bool region = addr & 0x0200; + if(ram_readable[region] == false) return 0x00; + return board.prgram.read((region * 0x0200) + (addr & 0x01ff)); +} + +void ram_write(unsigned addr, uint8 data) { + if(ram_enable == false) return; + bool region = addr & 0x0200; + if(ram_writable[region] == false) return; + return board.prgram.write((region * 0x0200) + (addr & 0x01ff), data); +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr & 0xe001) { + case 0x8000: + chr_mode = data & 0x80; + prg_mode = data & 0x40; + ram_enable = data & 0x20; + bank_select = data & 0x07; + if(ram_enable == false) { + for(auto &n : ram_readable) n = false; + for(auto &n : ram_writable) n = false; + } + break; + + case 0x8001: + switch(bank_select) { + case 0: chr_bank[0] = data & ~1; break; + case 1: chr_bank[1] = data & ~1; break; + case 2: chr_bank[2] = data; break; + case 3: chr_bank[3] = data; break; + case 4: chr_bank[4] = data; break; + case 5: chr_bank[5] = data; break; + case 6: prg_bank[0] = data & 0x3f; break; + case 7: prg_bank[1] = data & 0x3f; break; + } + break; + + case 0xa000: + mirror = data & 0x01; + break; + + case 0xa001: + if(ram_enable == false) break; + ram_readable[1] = data & 0x80; + ram_writable[1] = data & 0x40; + ram_readable[0] = data & 0x20; + ram_writable[0] = data & 0x10; + break; + + case 0xc000: + irq_latch = data; + break; + + case 0xc001: + irq_counter = 0; + break; + + case 0xe000: + irq_enable = false; + irq_line = 0; + break; + + case 0xe001: + irq_enable = true; + break; + } +} + +void power() { +} + +void reset() { + chr_mode = 0; + prg_mode = 0; + ram_enable = 0; + bank_select = 0; + for(auto &n : prg_bank) n = 0; + for(auto &n : chr_bank) n = 0; + mirror = 0; + for(auto &n : ram_readable) n = 0; + for(auto &n : ram_writable) n = 0; + irq_latch = 0; + irq_counter = 0; + irq_enable = 0; + irq_delay = 0; + irq_line = 0; + + chr_abus = 0; +} + +void serialize(serializer &s) { + s.integer(chr_mode); + s.integer(prg_mode); + s.integer(ram_enable); + s.integer(bank_select); + for(auto &n : prg_bank) s.integer(n); + for(auto &n : chr_bank) s.integer(n); + s.integer(mirror); + for(auto &n : ram_readable) s.integer(n); + for(auto &n : ram_writable) s.integer(n); + s.integer(irq_latch); + s.integer(irq_counter); + s.integer(irq_enable); + s.integer(irq_delay); + s.integer(irq_line); + + s.integer(chr_abus); +} + +MMC6(Board &board) : Chip(board) { +} + +}; diff --git a/nes/cartridge/chip/vrc1.cpp b/nes/cartridge/chip/vrc1.cpp new file mode 100755 index 00000000..a64c0fa1 --- /dev/null +++ b/nes/cartridge/chip/vrc1.cpp @@ -0,0 +1,80 @@ +struct VRC1 : Chip { + +uint4 prg_bank[3]; +uint4 chr_banklo[2]; +bool chr_bankhi[2]; +bool mirror; + +unsigned prg_addr(unsigned addr) const { + unsigned bank = 0x0f; + if((addr & 0xe000) == 0x8000) bank = prg_bank[0]; + if((addr & 0xe000) == 0xa000) bank = prg_bank[1]; + if((addr & 0xe000) == 0xc000) bank = prg_bank[2]; + return (bank * 0x2000) + (addr & 0x1fff); +} + +unsigned chr_addr(unsigned addr) const { + unsigned bank = chr_banklo[(bool)(addr & 0x1000)]; + bank |= chr_bankhi[(bool)(addr & 0x1000)] << 4; + return (bank * 0x1000) + (addr & 0x0fff); +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + } + throw; +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr & 0xf000) { + case 0x8000: + prg_bank[0] = data & 0x0f; + break; + + case 0x9000: + chr_bankhi[1] = data & 0x04; + chr_bankhi[0] = data & 0x02; + mirror = data & 0x01; + break; + + case 0xa000: + prg_bank[1] = data & 0x0f; + break; + + case 0xc000: + prg_bank[2] = data & 0x0f; + break; + + case 0xe000: + chr_banklo[0] = data & 0x0f; + break; + + case 0xf000: + chr_banklo[1] = data & 0x0f; + break; + } +} + +void power() { +} + +void reset() { + for(auto &n : prg_bank) n = 0; + for(auto &n : chr_banklo) n = 0; + for(auto &n : chr_bankhi) n = 0; + mirror = 0; +} + +void serialize(serializer &s) { + for(auto &n : prg_bank) s.integer(n); + for(auto &n : chr_banklo) s.integer(n); + for(auto &n : chr_bankhi) s.integer(n); + s.integer(mirror); +} + +VRC1(Board &board) : Chip(board) { +} + +}; diff --git a/nes/cartridge/chip/vrc2.cpp b/nes/cartridge/chip/vrc2.cpp new file mode 100755 index 00000000..207387fb --- /dev/null +++ b/nes/cartridge/chip/vrc2.cpp @@ -0,0 +1,110 @@ +struct VRC2 : Chip { + +uint5 prg_bank[2]; +uint8 chr_bank[8]; +uint2 mirror; +bool latch; + +unsigned prg_addr(unsigned addr) const { + unsigned bank; + switch(addr & 0xe000) { + case 0x8000: bank = prg_bank[0]; break; + case 0xa000: bank = prg_bank[1]; break; + case 0xc000: bank = 0x1e; break; + case 0xe000: bank = 0x1f; break; + } + return (bank * 0x2000) + (addr & 0x1fff); +} + +unsigned chr_addr(unsigned addr) const { + unsigned bank = chr_bank[addr / 0x0400]; + return (bank * 0x0400) + (addr & 0x03ff); +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) + case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) + } + throw; +} + +uint8 ram_read(unsigned addr) { + if(board.prgram.size == 0) { + if((addr & 0xf000) == 0x6000) return cpu.mdr() | latch; + return cpu.mdr(); + } + return board.prgram.read(addr & 0x1fff); +} + +void ram_write(unsigned addr, uint8 data) { + if(board.prgram.size == 0) { + if((addr & 0xf000) == 0x6000) latch = data & 0x01; + return; + } + return board.prgram.write(addr & 0x1fff, data); +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr) { + case 0x8000: case 0x8001: case 0x8002: case 0x8003: + prg_bank[0] = data & 0x1f; + break; + + case 0x9000: case 0x9001: case 0x9002: case 0x9003: + mirror = data & 0x03; + break; + + case 0xa000: case 0xa001: case 0xa002: case 0xa003: + prg_bank[1] = data & 0x1f; + break; + + case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xb001: chr_bank[0] = (chr_bank[0] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xb002: chr_bank[1] = (chr_bank[1] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xb003: chr_bank[1] = (chr_bank[1] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xc000: chr_bank[2] = (chr_bank[2] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xc001: chr_bank[2] = (chr_bank[2] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xc002: chr_bank[3] = (chr_bank[3] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xc003: chr_bank[3] = (chr_bank[3] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xd000: chr_bank[4] = (chr_bank[4] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xd001: chr_bank[4] = (chr_bank[4] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xd002: chr_bank[5] = (chr_bank[5] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xd003: chr_bank[5] = (chr_bank[5] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xe000: chr_bank[6] = (chr_bank[6] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xe001: chr_bank[6] = (chr_bank[6] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xe002: chr_bank[7] = (chr_bank[7] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xe003: chr_bank[7] = (chr_bank[7] & 0x0f) | ((data & 0x0f) << 4); break; + } +} + +void power() { +} + +void reset() { + for(auto &n : prg_bank) n = 0; + for(auto &n : chr_bank) n = 0; + mirror = 0; + latch = 0; +} + +void serialize(serializer &s) { + for(auto &n : prg_bank) s.integer(n); + for(auto &n : chr_bank) s.integer(n); + s.integer(mirror); + s.integer(latch); +} + +VRC2(Board &board) : Chip(board) { +} + +}; diff --git a/nes/cartridge/chip/vrc3.cpp b/nes/cartridge/chip/vrc3.cpp new file mode 100755 index 00000000..7ced8972 --- /dev/null +++ b/nes/cartridge/chip/vrc3.cpp @@ -0,0 +1,100 @@ +struct VRC3 : Chip { + +uint4 prg_bank; +bool irq_mode; +bool irq_enable; +bool irq_acknowledge; +uint16 irq_latch; +struct { + union { + uint16 w; + struct { uint8 order_lsb2(l, h); }; + }; +} irq_counter; +bool irq_line; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_enable) { + if(irq_mode == 0) { //16-bit + if(++irq_counter.w == 0) { + irq_line = 1; + irq_enable = irq_acknowledge; + irq_counter.w = irq_latch; + } + } + if(irq_mode == 1) { //8-bit + if(++irq_counter.l == 0) { + irq_line = 1; + irq_enable = irq_acknowledge; + irq_counter.l = irq_latch; + } + } + } + + cpu.set_irq_line(irq_line); + tick(); + } +} + +unsigned prg_addr(unsigned addr) const { + unsigned bank = (addr < 0xc000 ? (unsigned)prg_bank : 0x0f); + return (bank * 0x4000) + (addr & 0x3fff); +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr & 0xf000) { + case 0x8000: irq_latch = (irq_latch & 0xfff0) | ((data & 0x0f) << 0); break; + case 0x9000: irq_latch = (irq_latch & 0xff0f) | ((data & 0x0f) << 4); break; + case 0xa000: irq_latch = (irq_latch & 0xf0ff) | ((data & 0x0f) << 8); break; + case 0xb000: irq_latch = (irq_latch & 0x0fff) | ((data & 0x0f) << 12); break; + + case 0xc000: + irq_mode = data & 0x04; + irq_enable = data & 0x02; + irq_acknowledge = data & 0x01; + if(irq_enable) irq_counter.w = irq_latch; + break; + + case 0xd000: + irq_line = 0; + irq_enable = irq_acknowledge; + break; + + case 0xf000: + prg_bank = data & 0x0f; + break; + } +} + +void power() { +} + +void reset() { + prg_bank = 0; + irq_mode = 0; + irq_enable = 0; + irq_acknowledge = 0; + irq_latch = 0; + irq_counter.w = 0; + irq_line = 0; +} + +void serialize(serializer &s) { + s.integer(prg_bank); + s.integer(irq_mode); + s.integer(irq_enable); + s.integer(irq_acknowledge); + s.integer(irq_latch); + s.integer(irq_counter.w); + s.integer(irq_line); +} + +VRC3(Board &board) : Chip(board) { +} + +}; diff --git a/nes/cartridge/chip/vrc4.cpp b/nes/cartridge/chip/vrc4.cpp new file mode 100755 index 00000000..10c93ee9 --- /dev/null +++ b/nes/cartridge/chip/vrc4.cpp @@ -0,0 +1,184 @@ +struct VRC4 : Chip { + +bool prg_mode; +uint5 prg_bank[2]; +uint2 mirror; +uint8 chr_bank[8]; + +uint8 irq_latch; +bool irq_mode; +bool irq_enable; +bool irq_acknowledge; + +uint8 irq_counter; +signed irq_scalar; +bool irq_line; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_enable) { + if(irq_mode == 0) { + irq_scalar -= 3; + if(irq_scalar <= 0) { + irq_scalar += 341; + if(irq_counter == 0xff) { + irq_counter = irq_latch; + irq_line = 1; + } else { + irq_counter++; + } + } + } + + if(irq_mode == 1) { + if(irq_counter == 0xff) { + irq_counter = irq_latch; + irq_line = 1; + } else { + irq_counter++; + } + } + } + + cpu.set_irq_line(irq_line); + tick(); + } +} + +unsigned prg_addr(unsigned addr) const { + unsigned bank = 0, banks = board.prgrom.size / 0x2000; + switch(addr & 0xe000) { + case 0x8000: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break; + case 0xa000: bank = prg_bank[1]; break; + case 0xc000: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break; + case 0xe000: bank = banks - 1; break; + } + return (bank * 0x2000) + (addr & 0x1fff); +} + +unsigned chr_addr(unsigned addr) const { + unsigned bank = chr_bank[addr / 0x0400]; + return (bank * 0x0400) + (addr & 0x03ff); +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) + case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) + } + throw; +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr) { + case 0x8000: case 0x8001: case 0x8002: case 0x8003: + prg_bank[0] = data & 0x1f; + break; + + case 0x9000: case 0x9001: + mirror = data & 0x03; + break; + + case 0x9002: case 0x9003: + prg_mode = data & 0x02; + break; + + case 0xa000: case 0xa001: case 0xa002: case 0xa003: + prg_bank[1] = data & 0x1f; + break; + + case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xb001: chr_bank[0] = (chr_bank[0] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xb002: chr_bank[1] = (chr_bank[1] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xb003: chr_bank[1] = (chr_bank[1] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xc000: chr_bank[2] = (chr_bank[2] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xc001: chr_bank[2] = (chr_bank[2] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xc002: chr_bank[3] = (chr_bank[3] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xc003: chr_bank[3] = (chr_bank[3] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xd000: chr_bank[4] = (chr_bank[4] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xd001: chr_bank[4] = (chr_bank[4] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xd002: chr_bank[5] = (chr_bank[5] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xd003: chr_bank[5] = (chr_bank[5] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xe000: chr_bank[6] = (chr_bank[6] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xe001: chr_bank[6] = (chr_bank[6] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xe002: chr_bank[7] = (chr_bank[7] & 0xf0) | ((data & 0x0f) << 0); break; + case 0xe003: chr_bank[7] = (chr_bank[7] & 0x0f) | ((data & 0x0f) << 4); break; + + case 0xf000: + irq_latch = (irq_latch & 0xf0) | ((data & 0x0f) << 0); + break; + + case 0xf001: + irq_latch = (irq_latch & 0x0f) | ((data & 0x0f) << 4); + break; + + case 0xf002: + irq_mode = data & 0x04; + irq_enable = data & 0x02; + irq_acknowledge = data & 0x01; + if(irq_enable) { + irq_counter = irq_latch; + irq_scalar = 341; + } + irq_line = 0; + break; + + case 0xf003: + irq_enable = irq_acknowledge; + irq_line = 0; + break; + } +} + +void power() { +} + +void reset() { + prg_mode = 0; + for(auto &n : prg_bank) n = 0; + mirror = 0; + for(auto &n : chr_bank) n = 0; + + irq_latch = 0; + irq_mode = 0; + irq_enable = 0; + irq_acknowledge = 0; + + irq_counter = 0; + irq_scalar = 0; + irq_line = 0; +} + +void serialize(serializer &s) { + s.integer(prg_mode); + for(auto &n : prg_bank) s.integer(n); + s.integer(mirror); + for(auto &n : chr_bank) s.integer(n); + + s.integer(irq_latch); + s.integer(irq_mode); + s.integer(irq_enable); + s.integer(irq_acknowledge); + + s.integer(irq_counter); + s.integer(irq_scalar); + s.integer(irq_line); +} + +VRC4(Board &board) : Chip(board) { +} + +}; diff --git a/nes/cartridge/chip/vrc6.cpp b/nes/cartridge/chip/vrc6.cpp new file mode 100755 index 00000000..ed42a4ee --- /dev/null +++ b/nes/cartridge/chip/vrc6.cpp @@ -0,0 +1,321 @@ +struct VRC6 : Chip { + +uint8 prg_bank[2]; +uint8 chr_bank[8]; +uint2 mirror; +uint8 irq_latch; +bool irq_mode; +bool irq_enable; +bool irq_acknowledge; + +uint8 irq_counter; +signed irq_scalar; +bool irq_line; + +struct Pulse { + bool mode; + uint3 duty; + uint4 volume; + bool enable; + uint12 frequency; + + uint12 divider; + uint4 cycle; + uint4 output; + + void clock() { + if(--divider == 0) { + divider = frequency + 1; + cycle++; + output = (mode == 1 || cycle > duty) ? volume : (uint4)0; + } + + if(enable == false) output = 0; + } + + void serialize(serializer &s) { + s.integer(mode); + s.integer(duty); + s.integer(volume); + s.integer(enable); + s.integer(frequency); + + s.integer(divider); + s.integer(cycle); + s.integer(output); + } +} pulse1, pulse2; + +struct Sawtooth { + uint6 rate; + bool enable; + uint12 frequency; + + uint12 divider; + uint1 phase; + uint3 stage; + uint8 accumulator; + uint5 output; + + void clock() { + if(--divider == 0) { + divider = frequency + 1; + if(++phase == 0) { + accumulator += rate; + if(++stage == 7) { + stage = 0; + accumulator = 0; + } + } + } + + output = accumulator >> 3; + if(enable == false) output = 0; + } + + void serialize(serializer &s) { + s.integer(rate); + s.integer(enable); + s.integer(frequency); + + s.integer(divider); + s.integer(phase); + s.integer(stage); + s.integer(accumulator); + s.integer(output); + } +} sawtooth; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_enable) { + if(irq_mode == 0) { + irq_scalar -= 3; + if(irq_scalar <= 0) { + irq_scalar += 341; + if(irq_counter == 0xff) { + irq_counter = irq_latch; + irq_line = 1; + } else { + irq_counter++; + } + } + } + + if(irq_mode == 1) { + if(irq_counter == 0xff) { + irq_counter = irq_latch; + irq_line = 1; + } else { + irq_counter++; + } + } + } + cpu.set_irq_line(irq_line); + + pulse1.clock(); + pulse2.clock(); + sawtooth.clock(); + signed output = (pulse1.output + pulse2.output + sawtooth.output) << 7; + apu.set_sample(-output); + + tick(); + } +} + +unsigned prg_addr(unsigned addr) const { + if((addr & 0xc000) == 0x8000) return (prg_bank[0] << 14) | (addr & 0x3fff); + if((addr & 0xe000) == 0xc000) return (prg_bank[1] << 13) | (addr & 0x1fff); + if((addr & 0xe000) == 0xe000) return ( 0xff << 13) | (addr & 0x1fff); +} + +unsigned chr_addr(unsigned addr) const { + unsigned bank = chr_bank[(addr >> 10) & 7]; + return (bank << 10) | (addr & 0x03ff); +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) + case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) + } +} + +uint8 ram_read(unsigned addr) { + return board.prgram.data[addr & 0x1fff]; +} + +void ram_write(unsigned addr, uint8 data) { + board.prgram.data[addr & 0x1fff] = data; +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr) { + case 0x8000: case 0x8001: case 0x8002: case 0x8003: + prg_bank[0] = data; + break; + + case 0x9000: + pulse1.mode = data & 0x80; + pulse1.duty = (data & 0x70) >> 4; + pulse1.volume = data & 0x0f; + break; + + case 0x9001: + pulse1.frequency = (pulse1.frequency & 0x0f00) | ((data & 0xff) << 0); + break; + + case 0x9002: + pulse1.frequency = (pulse1.frequency & 0x00ff) | ((data & 0x0f) << 8); + pulse1.enable = data & 0x80; + break; + + case 0xa000: + pulse2.mode = data & 0x80; + pulse2.duty = (data & 0x70) >> 4; + pulse2.volume = data & 0x0f; + break; + + case 0xa001: + pulse2.frequency = (pulse2.frequency & 0x0f00) | ((data & 0xff) << 0); + break; + + case 0xa002: + pulse2.frequency = (pulse2.frequency & 0x00ff) | ((data & 0x0f) << 8); + pulse2.enable = data & 0x80; + break; + + case 0xb000: + sawtooth.rate = data & 0x3f; + break; + + case 0xb001: + sawtooth.frequency = (sawtooth.frequency & 0x0f00) | ((data & 0xff) << 0); + break; + + case 0xb002: + sawtooth.frequency = (sawtooth.frequency & 0x00ff) | ((data & 0x0f) << 8); + sawtooth.enable = data & 0x80; + break; + + case 0xb003: + mirror = (data >> 2) & 3; + break; + + case 0xc000: case 0xc001: case 0xc002: case 0xc003: + prg_bank[1] = data; + break; + + case 0xd000: case 0xd001: case 0xd002: case 0xd003: + chr_bank[0 + (addr & 3)] = data; + break; + + case 0xe000: case 0xe001: case 0xe002: case 0xe003: + chr_bank[4 + (addr & 3)] = data; + break; + + case 0xf000: + irq_latch = data; + break; + + case 0xf001: + irq_mode = data & 0x04; + irq_enable = data & 0x02; + irq_acknowledge = data & 0x01; + if(irq_enable) { + irq_counter = irq_latch; + irq_scalar = 341; + } + irq_line = 0; + break; + + case 0xf002: + irq_enable = irq_acknowledge; + irq_line = 0; + break; + } +} + +void power() { +} + +void reset() { + prg_bank[0] = 0; + prg_bank[1] = 0; + chr_bank[0] = 0; + chr_bank[1] = 0; + chr_bank[2] = 0; + chr_bank[3] = 0; + chr_bank[4] = 0; + chr_bank[5] = 0; + chr_bank[6] = 0; + chr_bank[7] = 0; + mirror = 0; + irq_latch = 0; + irq_mode = 0; + irq_enable = 0; + irq_acknowledge = 0; + + irq_counter = 0; + irq_scalar = 0; + irq_line = 0; + + pulse1.mode = 0; + pulse1.duty = 0; + pulse1.volume = 0; + pulse1.enable = 0; + pulse1.frequency = 0; + + pulse1.divider = 1; + pulse1.cycle = 0; + pulse1.output = 0; + + pulse2.mode = 0; + pulse2.duty = 0; + pulse2.volume = 0; + pulse2.enable = 0; + pulse2.frequency = 0; + + pulse2.divider = 1; + pulse2.cycle = 0; + pulse2.output = 0; + + sawtooth.rate = 0; + sawtooth.enable = 0; + sawtooth.frequency = 0; + + sawtooth.divider = 1; + sawtooth.phase = 0; + sawtooth.stage = 0; + sawtooth.accumulator = 0; + sawtooth.output = 0; +} + +void serialize(serializer &s) { + pulse1.serialize(s); + pulse2.serialize(s); + sawtooth.serialize(s); + + s.array(prg_bank); + s.array(chr_bank); + s.integer(mirror); + s.integer(irq_latch); + s.integer(irq_mode); + s.integer(irq_enable); + s.integer(irq_acknowledge); + + s.integer(irq_counter); + s.integer(irq_scalar); + s.integer(irq_line); +} + +VRC6(Board &board) : Chip(board) { +} + +}; diff --git a/nes/cartridge/chip/vrc7.cpp b/nes/cartridge/chip/vrc7.cpp new file mode 100755 index 00000000..fe777071 --- /dev/null +++ b/nes/cartridge/chip/vrc7.cpp @@ -0,0 +1,154 @@ +//Konami VRC7 +//Yamaha YM2413 OPLL audio - not emulated + +struct VRC7 : Chip { + +uint8 prg_bank[3]; +uint8 chr_bank[8]; +uint2 mirror; + +uint8 irq_latch; +bool irq_mode; +bool irq_enable; +bool irq_acknowledge; + +uint8 irq_counter; +signed irq_scalar; +bool irq_line; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_enable) { + if(irq_mode == 0) { + irq_scalar -= 3; + if(irq_scalar <= 0) { + irq_scalar += 341; + if(irq_counter == 0xff) { + irq_counter = irq_latch; + irq_line = 1; + } else { + irq_counter++; + } + } + } + + if(irq_mode == 1) { + if(irq_counter == 0xff) { + irq_counter = irq_latch; + irq_line = 1; + } else { + irq_counter++; + } + } + } + cpu.set_irq_line(irq_line); + + tick(); + } +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr) { + case 0x8000: prg_bank[0] = data; break; + case 0x8010: prg_bank[1] = data; break; + case 0x9000: prg_bank[2] = data; break; + case 0x9010: break; //APU addr port + case 0x9030: break; //APU data port + case 0xa000: chr_bank[0] = data; break; + case 0xa010: chr_bank[1] = data; break; + case 0xb000: chr_bank[2] = data; break; + case 0xb010: chr_bank[3] = data; break; + case 0xc000: chr_bank[4] = data; break; + case 0xc010: chr_bank[5] = data; break; + case 0xd000: chr_bank[6] = data; break; + case 0xd010: chr_bank[7] = data; break; + case 0xe000: mirror = data & 0x03; break; + + case 0xe010: + irq_latch = data; + break; + + case 0xf000: + irq_mode = data & 0x04; + irq_enable = data & 0x02; + irq_acknowledge = data & 0x01; + if(irq_enable) { + irq_counter = irq_latch; + irq_scalar = 341; + } + irq_line = 0; + break; + + case 0xf010: + irq_enable = irq_acknowledge; + irq_line = 0; + break; + } +} + +unsigned prg_addr(unsigned addr) const { + unsigned bank = 0; + switch(addr & 0xe000) { + case 0x8000: bank = prg_bank[0]; break; + case 0xa000: bank = prg_bank[1]; break; + case 0xc000: bank = prg_bank[2]; break; + case 0xe000: bank = 0xff; break; + } + return (bank * 0x2000) + (addr & 0x1fff); +} + +unsigned chr_addr(unsigned addr) const { + unsigned bank = chr_bank[addr / 0x0400]; + return (bank * 0x0400) + (addr & 0x03ff); +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) + case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) + } +} + +void power() { +} + +void reset() { + for(auto &n : prg_bank) n = 0; + for(auto &n : chr_bank) n = 0; + mirror = 0; + + irq_latch = 0; + irq_mode = 0; + irq_enable = 0; + irq_acknowledge = 0; + + irq_counter = 0; + irq_scalar = 0; + irq_line = 0; +} + +void serialize(serializer &s) { + s.array(prg_bank); + s.array(chr_bank); + s.integer(mirror); + + s.integer(irq_latch); + s.integer(irq_mode); + s.integer(irq_enable); + s.integer(irq_acknowledge); + + s.integer(irq_counter); + s.integer(irq_scalar); + s.integer(irq_line); +} + +VRC7(Board &board) : Chip(board) { +} + +}; diff --git a/nes/cartridge/ines.cpp b/nes/cartridge/ines.cpp new file mode 100755 index 00000000..b14f81c9 --- /dev/null +++ b/nes/cartridge/ines.cpp @@ -0,0 +1,150 @@ +static string iNES(const uint8_t *data, unsigned size) { + if(size < 16) return ""; + if(data[0] != 'N') return ""; + if(data[1] != 'E') return ""; + if(data[2] != 'S') return ""; + if(data[3] != 0x1a) return ""; + + string output; + + unsigned mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); + unsigned mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); + unsigned prgrom = data[4] * 0x4000; + unsigned chrrom = data[5] * 0x2000; + unsigned prgram = 0; + unsigned chrram = chrrom == 0 ? 8192 : 0; + +//print("iNES mapper: ", mapper, "\n"); + + output.append("cartridge\n"); + + switch(mapper) { + default: + output.append("\tboard type:NES-NROM-256\n"); + output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n"); + break; + + case 1: + output.append("\tboard type:NES-SXROM\n"); + output.append("\t\tchip type:MMC1B2\n"); + prgram = 8192; + break; + + case 2: + output.append("\tboard type:NES-UOROM\n"); + output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n"); + break; + + case 3: + output.append("\tboard type:NES-CNROM\n"); + output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n"); + break; + + case 4: + //MMC3 + output.append("\tboard type:NES-TLROM\n"); + output.append("\t\tchip type:MMC3B\n"); + prgram = 8192; + //MMC6 + //output.append("\tboard type:NES-HKROM\n"); + //output.append("\t\tchip type:MMC6\n"); + //prgram = 1024; + break; + + case 5: + output.append("\tboard type:NES-ELROM\n"); + output.append("\t\tchip type:MMC5\n"); + prgram = 65536; + break; + + case 7: + output.append("\tboard type:NES-AOROM\n"); + break; + + case 9: + output.append("\tboard type:NES-PNROM\n"); + output.append("\t\tchip type:MMC2\n"); + prgram = 8192; + break; + + case 10: + output.append("\tboard type:NES-FKROM\n"); + output.append("\t\tchip type:MMC4\n"); + prgram = 8192; + break; + + case 16: + output.append("\tboard type:BANDAI-FCG\n"); + output.append("\t\tchip type:LZ93D50\n"); + break; + + case 21: + case 23: + case 25: + //VRC4 + output.append("\tboard type:KONAMI-VRC-4\n"); + output.append("\t\tchip type:VRC4\n"); + output.append("\t\t\tpinout a0=1 a1=0\n"); + prgram = 8192; + break; + + case 22: + //VRC2 + output.append("\tboard type:KONAMI-VRC-2\n"); + output.append("\t\tchip type:VRC2\n"); + output.append("\t\t\tpinout a0=0 a1=1\n"); + break; + + case 24: + output.append("\tboard type:KONAMI-VRC-6\n"); + output.append("\t\tchip type:VRC6\n"); + break; + + case 26: + output.append("\tboard type:KONAMI-VRC-6\n"); + output.append("\t\tchip type:VRC6\n"); + prgram = 8192; + break; + + case 34: + output.append("\tboard type:NES-BNROM\n"); + output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n"); + break; + + case 66: + output.append("\tboard type:NES-GNROM\n"); + output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n"); + break; + + case 69: + output.append("\tboard type:SUNSOFT-5B\n"); + output.append("\t\tchip type:5B\n"); + prgram = 8192; + break; + + case 73: + output.append("\tboard type:KONAMI-VRC-3\n"); + output.append("\t\tchip type:VRC3\n"); + output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n"); + prgram = 8192; + break; + + case 75: + output.append("\tboard type:KONAMI-VRC-1\n"); + output.append("\t\tchip type:VRC1\n"); + break; + + case 85: + output.append("\tboard type:KONAMI-VRC-7\n"); + output.append("\t\tchip type:VRC7\n"); + prgram = 8192; + break; + } + + output.append("\t\tprg rom=", prgrom, " ram=", prgram, "\n"); + output.append("\t\tchr rom=", chrrom, " ram=", chrram, "\n"); + +//print(output, "\n"); + + return output; +} diff --git a/nes/cheat/cheat.cpp b/nes/cheat/cheat.cpp new file mode 100755 index 00000000..9a96deea --- /dev/null +++ b/nes/cheat/cheat.cpp @@ -0,0 +1,88 @@ +#include + +namespace NES { + +Cheat cheat; + +bool Cheat::decode(const string &code_, unsigned &addr, unsigned &data, unsigned &comp) { + static bool initialize = false; + static uint8 mapProActionReplay[256], mapGameGenie[256]; + + if(initialize == false) { + initialize = true; + + for(auto &n : mapProActionReplay) n = ~0; + mapProActionReplay['0'] = 0; mapProActionReplay['1'] = 1; mapProActionReplay['2'] = 2; mapProActionReplay['3'] = 3; + mapProActionReplay['4'] = 4; mapProActionReplay['5'] = 5; mapProActionReplay['6'] = 6; mapProActionReplay['7'] = 7; + mapProActionReplay['8'] = 8; mapProActionReplay['9'] = 9; mapProActionReplay['A'] = 10; mapProActionReplay['B'] = 11; + mapProActionReplay['C'] = 12; mapProActionReplay['D'] = 13; mapProActionReplay['E'] = 14; mapProActionReplay['F'] = 15; + + for(auto &n : mapGameGenie) n = ~0; + mapGameGenie['A'] = 0; mapGameGenie['P'] = 1; mapGameGenie['Z'] = 2; mapGameGenie['L'] = 3; + mapGameGenie['G'] = 4; mapGameGenie['I'] = 5; mapGameGenie['T'] = 6; mapGameGenie['Y'] = 7; + mapGameGenie['E'] = 8; mapGameGenie['O'] = 9; mapGameGenie['X'] = 10; mapGameGenie['U'] = 11; + mapGameGenie['K'] = 12; mapGameGenie['S'] = 13; mapGameGenie['V'] = 14; mapGameGenie['N'] = 15; + } + + string code = code_; + code.upper(); + unsigned length = code.length(), bits = 0; + + if(code.wildcard("????:??")) { + code = { substr(code, 0, 4), substr(code, 5, 2) }; + for(unsigned n = 0; n < 6; n++) if(mapProActionReplay[code[n]] > 15) return false; + bits = hex(code); + addr = (bits >> 8) & 0xffff; + data = (bits >> 0) & 0xff; + comp = ~0; + return true; + } + + if(code.wildcard("????:??:??")) { + code = { substr(code, 0, 4), substr(code, 5, 2), substr(code, 8, 2) }; + for(unsigned n = 0; n < 8; n++) if(mapProActionReplay[code[n]] > 15) return false; + bits = hex(code); + addr = (bits >> 16) & 0xffff; + data = (bits >> 8) & 0xff; + comp = (bits >> 0) & 0xff; + return true; + } + + if(length == 6) { + for(unsigned n = 0; n < 6; n++) if(mapGameGenie[code[n]] > 15) return false; + for(unsigned n = 0; n < 6; n++) bits |= mapGameGenie[code[n]] << (20 - n * 4); + unsigned addrTable[] = { 10, 9, 8, 7, 2, 1, 0, 19, 14, 13, 12, 11, 6, 5, 4 }; + unsigned dataTable[] = { 23, 18, 17, 16, 3, 22, 21, 20 }; + + addr = 0x8000, data = 0x00, comp = ~0; + for(unsigned n = 0; n < 15; n++) addr |= bits & (1 << addrTable[n]) ? 0x4000 >> n : 0; + for(unsigned n = 0; n < 8; n++) data |= bits & (1 << dataTable[n]) ? 0x80 >> n : 0; + return true; + } + + if(length == 8) { + for(unsigned n = 0; n < 8; n++) if(mapGameGenie[code[n]] > 15) return false; + for(unsigned n = 0; n < 8; n++) bits |= mapGameGenie[code[n]] << (28 - n * 4); + unsigned addrTable[] = { 18, 17, 16, 15, 10, 9, 8, 27, 22, 21, 20, 19, 14, 13, 12 }; + unsigned dataTable[] = { 31, 26, 25, 24, 3, 30, 29, 28 }; + unsigned compTable[] = { 7, 2, 1, 0, 11, 6, 5,4 }; + + addr = 0x8000, data = 0x00, comp = 0x00; + for(unsigned n = 0; n < 15; n++) addr |= bits & (1 << addrTable[n]) ? 0x4000 >> n : 0; + for(unsigned n = 0; n < 8; n++) data |= bits & (1 << dataTable[n]) ? 0x80 >> n : 0; + for(unsigned n = 0; n < 8; n++) comp |= bits & (1 << compTable[n]) ? 0x80 >> n : 0; + return true; + } + + return false; +} + +void Cheat::synchronize() { + for(auto &n : override) n = false; + + for(unsigned n = 0; n < size(); n++) { + override[operator[](n).addr] = true; + } +} + +} diff --git a/nes/cheat/cheat.hpp b/nes/cheat/cheat.hpp new file mode 100755 index 00000000..4446a52b --- /dev/null +++ b/nes/cheat/cheat.hpp @@ -0,0 +1,14 @@ +struct CheatCode { + unsigned addr; + unsigned data; + unsigned comp; +}; + +struct Cheat : public linear_vector { + static bool decode(const string &code, unsigned &addr, unsigned &data, unsigned &comp); + + void synchronize(); + bool override[65536]; +}; + +extern Cheat cheat; diff --git a/nes/cpu/core/core.cpp b/nes/cpu/core/core.cpp new file mode 100755 index 00000000..f4394e93 --- /dev/null +++ b/nes/cpu/core/core.cpp @@ -0,0 +1,10 @@ +#define call(op) (this->*op)() +#define L interrupt_test(); + +#include "interrupt.cpp" +#include "opcodes.cpp" +#include "exec.cpp" +#include "disassembler.cpp" + +#undef L +#undef call diff --git a/nes/cpu/core/core.hpp b/nes/cpu/core/core.hpp new file mode 100755 index 00000000..0a07d4c4 --- /dev/null +++ b/nes/cpu/core/core.hpp @@ -0,0 +1,117 @@ +struct Flags { + bool n, v, d, i, z, c; + + inline operator unsigned() { + return (n << 7) | (v << 6) | (d << 3) | (i << 2) | (z << 1) | (c << 0); + } + + inline Flags& operator=(uint8 data) { + n = data & 0x80; v = data & 0x40; + d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01; + return *this; + } +}; + +struct Registers { + uint8 mdr; + uint16 pc; + uint8 a, x, y, s; + Flags p; +} regs; + +struct Register16 { + union { + uint16 w; + struct { uint8 order_lsb2(l, h); }; + }; +} abs, iabs; + +uint8 rd; +uint8 zp; +uint16 aa; + +//interrupt.cpp +void interrupt(); +void interrupt_test(); +void set_nmi_line(bool); +void set_irq_line(bool); +void set_irq_apu_line(bool); + +//opcodes.cpp +void opf_asl(); +void opf_adc(); +void opf_and(); +void opf_bit(); +void opf_cmp(); +void opf_cpx(); +void opf_cpy(); +void opf_dec(); +void opf_eor(); +void opf_inc(); +void opf_lda(); +void opf_ldx(); +void opf_ldy(); +void opf_lsr(); +void opf_ora(); +void opf_rla(); +void opf_rol(); +void opf_ror(); +void opf_rra(); +void opf_sbc(); +void opf_sla(); +void opf_sra(); + +void opi_branch(bool condition); +void opi_clear_flag(bool &flag); +void opi_decrement(uint8 &r); +void opi_increment(uint8 &r); +void opi_pull(uint8 &r); +void opi_push(uint8 &r); +template void opi_read_absolute(); +template void opi_read_absolute_x(); +template void opi_read_absolute_y(); +template void opi_read_immediate(); +template void opi_read_indirect_zero_page_x(); +template void opi_read_indirect_zero_page_y(); +template void opi_read_zero_page(); +template void opi_read_zero_page_x(); +template void opi_read_zero_page_y(); +template void opi_rmw_absolute(); +template void opi_rmw_absolute_x(); +template void opi_rmw_zero_page(); +template void opi_rmw_zero_page_x(); +void opi_set_flag(bool &flag); +template void opi_shift(); +void opi_store_absolute(uint8 &r); +void opi_store_absolute_x(uint8 &r); +void opi_store_absolute_y(uint8 &r); +void opi_store_indirect_zero_page_x(uint8 &r); +void opi_store_indirect_zero_page_y(uint8 &r); +void opi_store_zero_page(uint8 &r); +void opi_store_zero_page_x(uint8 &r); +void opi_store_zero_page_y(uint8 &r); +void opi_transfer(uint8 &s, uint8 &d, bool flag); + +void op_brk(); +void op_jmp_absolute(); +void op_jmp_indirect_absolute(); +void op_jsr_absolute(); +void op_nop(); +void op_php(); +void op_plp(); +void op_rti(); +void op_rts(); + +void opill_arr_immediate(); +void opill_nop_absolute(); +void opill_nop_absolute_x(); +void opill_nop_immediate(); +void opill_nop_implied(); +void opill_nop_zero_page(); +void opill_nop_zero_page_x(); + +//exec.cpp +void op_exec(); + +//disassembler.cpp +string disassemble(); diff --git a/nes/cpu/core/disassembler.cpp b/nes/cpu/core/disassembler.cpp new file mode 100755 index 00000000..24095bc9 --- /dev/null +++ b/nes/cpu/core/disassembler.cpp @@ -0,0 +1,194 @@ +string CPU::disassemble() { + string output = { hex<4>(regs.pc), " " }; + + auto abs = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)) }; }; + auto abx = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)), ",x" }; }; + auto aby = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)), ",y" }; }; + auto iab = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)), ")" }; }; + auto imm = [&]() -> string { return { "#$", hex<2>(bus.read(regs.pc + 1)) }; }; + auto imp = [&]() -> string { return ""; }; + auto izx = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 1)), ",x)" }; }; + auto izy = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 1)), "),y" }; }; + auto rel = [&]() -> string { return { "$", hex<4>((regs.pc + 2) + (int8)bus.read(regs.pc + 1)) }; }; + auto zpg = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)) }; }; + auto zpx = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)), ",x" }; }; + auto zpy = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)), ",y" }; }; + + #define op(byte, prefix, mode) \ + case byte: output.append(#prefix, " ", mode()); \ + break + + uint8 opcode = bus.read(regs.pc); + switch(opcode) { + op(0x00, brk, imm); + op(0x01, ora, izx); + op(0x05, ora, zpg); + op(0x06, asl, zpg); + op(0x08, php, imp); + op(0x09, ora, imm); + op(0x0a, asl, imp); + op(0x0d, ora, abs); + op(0x0e, asl, abs); + op(0x10, bpl, rel); + op(0x11, ora, izy); + op(0x15, ora, zpx); + op(0x16, asl, zpx); + op(0x18, clc, imp); + op(0x19, ora, aby); + op(0x1d, ora, abx); + op(0x1e, asl, abx); + op(0x20, jsr, abs); + op(0x21, and, izx); + op(0x24, bit, zpg); + op(0x25, and, zpg); + op(0x26, rol, zpg); + op(0x28, plp, imp); + op(0x29, and, imm); + op(0x2a, rol, imp); + op(0x2c, bit, abs); + op(0x2d, and, abs); + op(0x2e, rol, abs); + op(0x30, bmi, rel); + op(0x31, and, izy); + op(0x35, and, zpx); + op(0x36, rol, zpx); + op(0x38, sec, imp); + op(0x39, and, aby); + op(0x3d, and, abx); + op(0x3e, rol, abx); + op(0x40, rti, imp); + op(0x41, eor, izx); + op(0x45, eor, zpg); + op(0x46, lsr, zpg); + op(0x48, pha, imp); + op(0x49, eor, imm); + op(0x4a, lsr, imp); + op(0x4c, jmp, abs); + op(0x4d, eor, abs); + op(0x4e, lsr, abs); + op(0x50, bvc, rel); + op(0x51, eor, izy); + op(0x55, eor, zpx); + op(0x56, lsr, zpx); + op(0x58, cli, imp); + op(0x59, eor, aby); + op(0x5a, phy, imp); + op(0x5d, eor, abx); + op(0x5e, lsr, abx); + op(0x60, rts, imp); + op(0x61, adc, izx); + op(0x65, adc, zpg); + op(0x66, ror, zpg); + op(0x68, pla, imp); + op(0x69, adc, imm); + op(0x6a, ror, imp); + op(0x6c, jmp, iab); + op(0x6d, adc, abs); + op(0x6e, ror, abs); + op(0x70, bvs, rel); + op(0x71, adc, izy); + op(0x75, adc, zpx); + op(0x76, ror, zpx); + op(0x78, sei, imp); + op(0x79, adc, aby); + op(0x7a, ply, imp); + op(0x7d, adc, abx); + op(0x7e, ror, abx); + op(0x81, sta, izx); + op(0x84, sty, zpg); + op(0x85, sta, zpg); + op(0x86, stx, zpg); + op(0x88, dey, imp); + op(0x8a, txa, imp); + op(0x8c, sty, abs); + op(0x8d, sta, abs); + op(0x8e, stx, abs); + op(0x90, bcc, rel); + op(0x91, sta, izy); + op(0x94, sty, zpx); + op(0x95, sta, zpx); + op(0x96, stx, zpy); + op(0x98, tya, imp); + op(0x99, sta, aby); + op(0x9a, txs, imp); + op(0x9d, sta, abx); + op(0xa0, ldy, imm); + op(0xa1, lda, izx); + op(0xa2, ldx, imm); + op(0xa4, ldy, zpg); + op(0xa5, lda, zpg); + op(0xa6, ldx, zpg); + op(0xa8, tay, imp); + op(0xa9, lda, imm); + op(0xaa, tax, imp); + op(0xac, ldy, abs); + op(0xad, lda, abs); + op(0xae, ldx, abs); + op(0xb0, bcs, rel); + op(0xb1, lda, izy); + op(0xb4, ldy, zpx); + op(0xb5, lda, zpx); + op(0xb6, ldx, zpy); + op(0xb8, clv, imp); + op(0xb9, lda, aby); + op(0xba, tsx, imp); + op(0xbc, ldy, abx); + op(0xbd, lda, abx); + op(0xbe, ldx, aby); + op(0xc0, cpy, imm); + op(0xc1, cmp, izx); + op(0xc4, cpy, zpg); + op(0xc5, cmp, zpg); + op(0xc6, dec, zpg); + op(0xc8, iny, imp); + op(0xc9, cmp, imm); + op(0xca, dex, imp); + op(0xcc, cpy, abs); + op(0xcd, cmp, abs); + op(0xce, dec, abs); + op(0xd0, bne, rel); + op(0xd1, cmp, izy); + op(0xd5, cmp, zpx); + op(0xd6, dec, zpx); + op(0xd8, cld, imp); + op(0xd9, cmp, aby); + op(0xda, phx, imp); + op(0xdd, cmp, abx); + op(0xde, dec, abx); + op(0xe0, cpx, imm); + op(0xe1, sbc, izx); + op(0xe4, cpx, zpg); + op(0xe5, sbc, zpg); + op(0xe6, inc, zpg); + op(0xe8, inx, imp); + op(0xe9, sbc, imm); + op(0xea, nop, imp); + op(0xec, cpx, abs); + op(0xed, sbc, abs); + op(0xee, inc, abs); + op(0xf0, beq, rel); + op(0xf1, sbc, izy); + op(0xf5, sbc, zpx); + op(0xf6, inc, zpx); + op(0xf8, sed, imp); + op(0xf9, sbc, aby); + op(0xfa, plx, imp); + op(0xfd, sbc, abx); + op(0xfe, inc, abx); + + default: output.append("$", hex<2>(opcode)); break; + } + + #undef op + + output.append(" "); + output[20] = 0; + + output.append( + "A:", hex<2>(regs.a), " X:", hex<2>(regs.x), " Y:", hex<2>(regs.y), " S:", hex<2>(regs.s), " ", + regs.p.n ? "N" : "n", regs.p.v ? "V" : "v", regs.p.d ? "D" : "d", + regs.p.i ? "I" : "i", regs.p.z ? "Z" : "z", regs.p.c ? "C" : "c" + ); + + return output; +} diff --git a/nes/cpu/core/exec.cpp b/nes/cpu/core/exec.cpp new file mode 100755 index 00000000..b299d0c5 --- /dev/null +++ b/nes/cpu/core/exec.cpp @@ -0,0 +1,196 @@ +//I = illegal instruction (only used as a visual indicator) +#define I + +void CPU::op_exec() { + uint8 opcode = op_readpci(); + switch(opcode) { + case 0x00: return op_brk(); + case 0x01: return opi_read_indirect_zero_page_x<&CPU::opf_ora>(); + I case 0x04: return opill_nop_zero_page(); + case 0x05: return opi_read_zero_page<&CPU::opf_ora>(); + case 0x06: return opi_rmw_zero_page<&CPU::opf_asl>(); + case 0x08: return op_php(); + case 0x09: return opi_read_immediate<&CPU::opf_ora>(); + case 0x0a: return opi_shift<&CPU::opf_sla>(); + I case 0x0c: return opill_nop_absolute(); + case 0x0d: return opi_read_absolute<&CPU::opf_ora>(); + case 0x0e: return opi_rmw_absolute<&CPU::opf_asl>(); + case 0x10: return opi_branch(regs.p.n == 0); + case 0x11: return opi_read_indirect_zero_page_y<&CPU::opf_ora>(); + I case 0x14: return opill_nop_zero_page_x(); + case 0x15: return opi_read_zero_page_x<&CPU::opf_ora>(); + case 0x16: return opi_rmw_zero_page_x<&CPU::opf_asl>(); + case 0x18: return opi_clear_flag(regs.p.c); + case 0x19: return opi_read_absolute_y<&CPU::opf_ora>(); + I case 0x1a: return opill_nop_implied(); + I case 0x1c: return opill_nop_absolute_x(); + case 0x1d: return opi_read_absolute_x<&CPU::opf_ora>(); + case 0x1e: return opi_rmw_absolute_x<&CPU::opf_asl>(); + case 0x20: return op_jsr_absolute(); + case 0x21: return opi_read_indirect_zero_page_x<&CPU::opf_and>(); + case 0x24: return opi_read_zero_page<&CPU::opf_bit>(); + case 0x25: return opi_read_zero_page<&CPU::opf_and>(); + case 0x26: return opi_rmw_zero_page<&CPU::opf_rol>(); + case 0x28: return op_plp(); + case 0x29: return opi_read_immediate<&CPU::opf_and>(); + case 0x2a: return opi_shift<&CPU::opf_rla>(); + case 0x2c: return opi_read_absolute<&CPU::opf_bit>(); + case 0x2d: return opi_read_absolute<&CPU::opf_and>(); + case 0x2e: return opi_rmw_absolute<&CPU::opf_rol>(); + case 0x30: return opi_branch(regs.p.n == 1); + case 0x31: return opi_read_indirect_zero_page_y<&CPU::opf_and>(); + I case 0x34: return opill_nop_zero_page_x(); + case 0x35: return opi_read_zero_page_x<&CPU::opf_and>(); + case 0x36: return opi_rmw_zero_page_x<&CPU::opf_rol>(); + case 0x38: return opi_set_flag(regs.p.c); + case 0x39: return opi_read_absolute_y<&CPU::opf_and>(); + I case 0x3a: return opill_nop_implied(); + I case 0x3c: return opill_nop_absolute_x(); + case 0x3d: return opi_read_absolute_x<&CPU::opf_and>(); + case 0x3e: return opi_rmw_absolute_x<&CPU::opf_rol>(); + case 0x40: return op_rti(); + case 0x41: return opi_read_indirect_zero_page_x<&CPU::opf_eor>(); + I case 0x44: return opill_nop_zero_page(); + case 0x45: return opi_read_zero_page<&CPU::opf_eor>(); + case 0x46: return opi_rmw_zero_page<&CPU::opf_lsr>(); + case 0x48: return opi_push(regs.a); + case 0x49: return opi_read_immediate<&CPU::opf_eor>(); + case 0x4a: return opi_shift<&CPU::opf_sra>(); + case 0x4c: return op_jmp_absolute(); + case 0x4d: return opi_read_absolute<&CPU::opf_eor>(); + case 0x4e: return opi_rmw_absolute<&CPU::opf_lsr>(); + case 0x50: return opi_branch(regs.p.v == 0); + case 0x51: return opi_read_indirect_zero_page_y<&CPU::opf_eor>(); + I case 0x54: return opill_nop_zero_page_x(); + case 0x55: return opi_read_zero_page_x<&CPU::opf_eor>(); + case 0x56: return opi_rmw_zero_page_x<&CPU::opf_lsr>(); + case 0x58: return opi_clear_flag(regs.p.i); + case 0x59: return opi_read_absolute_y<&CPU::opf_eor>(); + I case 0x5a: return opill_nop_implied(); + I case 0x5c: return opill_nop_absolute_x(); + case 0x5d: return opi_read_absolute_x<&CPU::opf_eor>(); + case 0x5e: return opi_rmw_absolute_x<&CPU::opf_lsr>(); + case 0x60: return op_rts(); + case 0x61: return opi_read_indirect_zero_page_x<&CPU::opf_adc>(); + I case 0x64: return opill_nop_zero_page(); + case 0x65: return opi_read_zero_page<&CPU::opf_adc>(); + case 0x66: return opi_rmw_zero_page<&CPU::opf_ror>(); + case 0x68: return opi_pull(regs.a); + case 0x69: return opi_read_immediate<&CPU::opf_adc>(); + case 0x6a: return opi_shift<&CPU::opf_rra>(); + I case 0x6b: return opill_arr_immediate(); + case 0x6c: return op_jmp_indirect_absolute(); + case 0x6d: return opi_read_absolute<&CPU::opf_adc>(); + case 0x6e: return opi_rmw_absolute<&CPU::opf_ror>(); + case 0x70: return opi_branch(regs.p.v == 1); + I case 0x74: return opill_nop_zero_page_x(); + case 0x71: return opi_read_indirect_zero_page_y<&CPU::opf_adc>(); + case 0x75: return opi_read_zero_page_x<&CPU::opf_adc>(); + case 0x76: return opi_rmw_zero_page_x<&CPU::opf_ror>(); + case 0x78: return opi_set_flag(regs.p.i); + case 0x79: return opi_read_absolute_y<&CPU::opf_adc>(); + I case 0x7a: return opill_nop_implied(); + I case 0x7c: return opill_nop_absolute_x(); + case 0x7d: return opi_read_absolute_x<&CPU::opf_adc>(); + case 0x7e: return opi_rmw_absolute_x<&CPU::opf_ror>(); + I case 0x80: return opill_nop_absolute(); + case 0x81: return opi_store_indirect_zero_page_x(regs.a); + I case 0x82: return opill_nop_immediate(); + case 0x84: return opi_store_zero_page(regs.y); + case 0x85: return opi_store_zero_page(regs.a); + case 0x86: return opi_store_zero_page(regs.x); + case 0x88: return opi_decrement(regs.y); + I case 0x89: return opill_nop_immediate(); + case 0x8a: return opi_transfer(regs.x, regs.a, 1); + case 0x8c: return opi_store_absolute(regs.y); + case 0x8d: return opi_store_absolute(regs.a); + case 0x8e: return opi_store_absolute(regs.x); + case 0x90: return opi_branch(regs.p.c == 0); + case 0x91: return opi_store_indirect_zero_page_y(regs.a); + case 0x94: return opi_store_zero_page_x(regs.y); + case 0x95: return opi_store_zero_page_x(regs.a); + case 0x96: return opi_store_zero_page_y(regs.x); + case 0x98: return opi_transfer(regs.y, regs.a, 1); + case 0x99: return opi_store_absolute_y(regs.a); + case 0x9a: return opi_transfer(regs.x, regs.s, 0); + case 0x9d: return opi_store_absolute_x(regs.a); + case 0xa0: return opi_read_immediate<&CPU::opf_ldy>(); + case 0xa1: return opi_read_indirect_zero_page_x<&CPU::opf_lda>(); + case 0xa2: return opi_read_immediate<&CPU::opf_ldx>(); + case 0xa4: return opi_read_zero_page<&CPU::opf_ldy>(); + case 0xa5: return opi_read_zero_page<&CPU::opf_lda>(); + case 0xa6: return opi_read_zero_page<&CPU::opf_ldx>(); + case 0xa8: return opi_transfer(regs.a, regs.y, 1); + case 0xa9: return opi_read_immediate<&CPU::opf_lda>(); + case 0xaa: return opi_transfer(regs.a, regs.x, 1); + case 0xac: return opi_read_absolute<&CPU::opf_ldy>(); + case 0xad: return opi_read_absolute<&CPU::opf_lda>(); + case 0xae: return opi_read_absolute<&CPU::opf_ldx>(); + case 0xb0: return opi_branch(regs.p.c == 1); + case 0xb1: return opi_read_indirect_zero_page_y<&CPU::opf_lda>(); + case 0xb4: return opi_read_zero_page_x<&CPU::opf_ldy>(); + case 0xb5: return opi_read_zero_page_x<&CPU::opf_lda>(); + case 0xb6: return opi_read_zero_page_y<&CPU::opf_ldx>(); + case 0xb8: return opi_clear_flag(regs.p.v); + case 0xb9: return opi_read_absolute_y<&CPU::opf_lda>(); + case 0xba: return opi_transfer(regs.s, regs.x, 1); + case 0xbc: return opi_read_absolute_x<&CPU::opf_ldy>(); + case 0xbd: return opi_read_absolute_x<&CPU::opf_lda>(); + case 0xbe: return opi_read_absolute_y<&CPU::opf_ldx>(); + case 0xc0: return opi_read_immediate<&CPU::opf_cpy>(); + case 0xc1: return opi_read_indirect_zero_page_x<&CPU::opf_cmp>(); + I case 0xc2: return opill_nop_immediate(); + case 0xc4: return opi_read_zero_page<&CPU::opf_cpy>(); + case 0xc5: return opi_read_zero_page<&CPU::opf_cmp>(); + case 0xc6: return opi_rmw_zero_page<&CPU::opf_dec>(); + case 0xc8: return opi_increment(regs.y); + case 0xc9: return opi_read_immediate<&CPU::opf_cmp>(); + case 0xca: return opi_decrement(regs.x); + case 0xcc: return opi_read_absolute<&CPU::opf_cpy>(); + case 0xcd: return opi_read_absolute<&CPU::opf_cmp>(); + case 0xce: return opi_rmw_absolute<&CPU::opf_dec>(); + case 0xd0: return opi_branch(regs.p.z == 0); + case 0xd1: return opi_read_indirect_zero_page_y<&CPU::opf_cmp>(); + I case 0xd4: return opill_nop_zero_page_x(); + case 0xd5: return opi_read_zero_page_x<&CPU::opf_cmp>(); + case 0xd6: return opi_rmw_zero_page_x<&CPU::opf_dec>(); + case 0xd8: return opi_clear_flag(regs.p.d); + case 0xd9: return opi_read_absolute_y<&CPU::opf_cmp>(); + I case 0xda: return opill_nop_implied(); + I case 0xdc: return opill_nop_absolute_x(); + case 0xdd: return opi_read_absolute_x<&CPU::opf_cmp>(); + case 0xde: return opi_rmw_absolute_x<&CPU::opf_dec>(); + case 0xe0: return opi_read_immediate<&CPU::opf_cpx>(); + case 0xe1: return opi_read_indirect_zero_page_x<&CPU::opf_sbc>(); + I case 0xe2: return opill_nop_immediate(); + case 0xe4: return opi_read_zero_page<&CPU::opf_cpx>(); + case 0xe5: return opi_read_zero_page<&CPU::opf_sbc>(); + case 0xe6: return opi_rmw_zero_page<&CPU::opf_inc>(); + case 0xe8: return opi_increment(regs.x); + case 0xe9: return opi_read_immediate<&CPU::opf_sbc>(); + case 0xea: return op_nop(); + I case 0xeb: return opi_read_immediate<&CPU::opf_sbc>(); + case 0xec: return opi_read_absolute<&CPU::opf_cpx>(); + case 0xed: return opi_read_absolute<&CPU::opf_sbc>(); + case 0xee: return opi_rmw_absolute<&CPU::opf_inc>(); + case 0xf0: return opi_branch(regs.p.z == 1); + case 0xf1: return opi_read_indirect_zero_page_y<&CPU::opf_sbc>(); + I case 0xf4: return opill_nop_zero_page_x(); + case 0xf5: return opi_read_zero_page_x<&CPU::opf_sbc>(); + case 0xf6: return opi_rmw_zero_page_x<&CPU::opf_inc>(); + case 0xf8: return opi_set_flag(regs.p.d); + case 0xf9: return opi_read_absolute_y<&CPU::opf_sbc>(); + I case 0xfa: return opill_nop_implied(); + I case 0xfc: return opill_nop_absolute_x(); + case 0xfd: return opi_read_absolute_x<&CPU::opf_sbc>(); + case 0xfe: return opi_rmw_absolute_x<&CPU::opf_inc>(); + } + +//return op_nop(); + + regs.pc--; + print("Unimplemented opcode: ", hex<4>(regs.pc), " = ", hex<2>(bus.read(regs.pc)), "\n"); + while(true) scheduler.exit(Scheduler::ExitReason::UnknownEvent); +} + +#undef I diff --git a/nes/cpu/core/interrupt.cpp b/nes/cpu/core/interrupt.cpp new file mode 100755 index 00000000..a3a76828 --- /dev/null +++ b/nes/cpu/core/interrupt.cpp @@ -0,0 +1,37 @@ +void CPU::interrupt() { + op_readpc(); + op_readpc(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + op_writesp(regs.p | 0x20); + uint16 vector = 0xfffe; //IRQ + if(status.nmi_pending) { + status.nmi_pending = false; + vector = 0xfffa; + } + abs.l = op_read(vector++); + regs.p.i = 1; + regs.p.d = 0; +L abs.h = op_read(vector++); + regs.pc = abs.w; +} + +void CPU::interrupt_test() { + status.interrupt_pending = ((status.irq_line | status.irq_apu_line) & ~regs.p.i) | status.nmi_pending; +} + +void CPU::set_nmi_line(bool line) { + //edge-sensitive (0->1) + if(!status.nmi_line && line) status.nmi_pending = true; + status.nmi_line = line; +} + +void CPU::set_irq_line(bool line) { + //level-sensitive + status.irq_line = line; +} + +void CPU::set_irq_apu_line(bool line) { + //level-sensitive + status.irq_apu_line = line; +} diff --git a/nes/cpu/core/opcodes.cpp b/nes/cpu/core/opcodes.cpp new file mode 100755 index 00000000..f6a131fc --- /dev/null +++ b/nes/cpu/core/opcodes.cpp @@ -0,0 +1,502 @@ +//opcode functions +//================ + +void CPU::opf_adc() { + signed result = regs.a + rd + regs.p.c; + regs.p.v = ~(regs.a ^ rd) & (regs.a ^ result) & 0x80; + regs.p.c = (result > 0xff); + regs.p.n = (result & 0x80); + regs.p.z = ((uint8)result == 0); + regs.a = result; +} + +void CPU::opf_and() { + regs.a &= rd; + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void CPU::opf_asl() { + regs.p.c = rd & 0x80; + rd <<= 1; + regs.p.n = (rd & 0x80); + regs.p.z = (rd == 0); +} + +void CPU::opf_bit() { + regs.p.n = (rd & 0x80); + regs.p.v = (rd & 0x40); + regs.p.z = ((rd & regs.a) == 0); +} + +void CPU::opf_cmp() { + signed r = regs.a - rd; + regs.p.n = (r & 0x80); + regs.p.z = (uint8)(r == 0); + regs.p.c = (r >= 0); +} + +void CPU::opf_cpx() { + signed r = regs.x - rd; + regs.p.n = (r & 0x80); + regs.p.z = (uint8)(r == 0); + regs.p.c = (r >= 0); +} + +void CPU::opf_cpy() { + signed r = regs.y - rd; + regs.p.n = (r & 0x80); + regs.p.z = (uint8)(r == 0); + regs.p.c = (r >= 0); +} + +void CPU::opf_dec() { + rd--; + regs.p.n = (rd & 0x80); + regs.p.z = (rd == 0); +} + +void CPU::opf_eor() { + regs.a ^= rd; + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void CPU::opf_inc() { + rd++; + regs.p.n = (rd & 0x80); + regs.p.z = (rd == 0); +} + +void CPU::opf_lda() { + regs.a = rd; + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void CPU::opf_ldx() { + regs.x = rd; + regs.p.n = (regs.x & 0x80); + regs.p.z = (regs.x == 0); +} + +void CPU::opf_ldy() { + regs.y = rd; + regs.p.n = (regs.y & 0x80); + regs.p.z = (regs.y == 0); +} + +void CPU::opf_lsr() { + regs.p.c = rd & 0x01; + rd >>= 1; + regs.p.n = (rd & 0x80); + regs.p.z = (rd == 0); +} + +void CPU::opf_ora() { + regs.a |= rd; + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void CPU::opf_rla() { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = regs.a & 0x80; + regs.a = (regs.a << 1) | carry; + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void CPU::opf_rol() { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = rd & 0x80; + rd = (rd << 1) | carry; + regs.p.n = (rd & 0x80); + regs.p.z = (rd == 0); +} + +void CPU::opf_ror() { + unsigned carry = (unsigned)regs.p.c << 7; + regs.p.c = rd & 0x01; + rd = carry | (rd >> 1); + regs.p.n = (rd & 0x80); + regs.p.z = (rd == 0); +} + +void CPU::opf_rra() { + unsigned carry = (unsigned)regs.p.c << 7; + regs.p.c = regs.a & 0x01; + regs.a = carry | (regs.a >> 1); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void CPU::opf_sbc() { + rd ^= 0xff; + return opf_adc(); +} + +void CPU::opf_sla() { + regs.p.c = regs.a & 0x80; + regs.a <<= 1; + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void CPU::opf_sra() { + regs.p.c = regs.a & 0x01; + regs.a >>= 1; + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +//opcode implementations +//====================== + +void CPU::opi_branch(bool condition) { + if(condition == false) { +L rd = op_readpci(); + } else { + rd = op_readpci(); + aa = regs.pc + (int8)rd; + op_page(regs.pc, aa); +L op_readpc(); + regs.pc = aa; + } +} + +void CPU::opi_clear_flag(bool &flag) { +L op_readpc(); + flag = 0; +} + +void CPU::opi_decrement(uint8 &r) { +L op_readpc(); + r--; + regs.p.n = (r & 0x80); + regs.p.z = (r == 0); +} + +void CPU::opi_increment(uint8 &r) { +L op_readpc(); + r++; + regs.p.n = (r & 0x80); + regs.p.z = (r == 0); +} + +void CPU::opi_pull(uint8 &r) { + op_readpc(); + op_readpc(); +L r = op_readsp(); + regs.p.n = (r & 0x80); + regs.p.z = (r == 0); +} + +void CPU::opi_push(uint8 &r) { + op_readpc(); +L op_writesp(r); +} + +template +void CPU::opi_read_absolute() { + abs.l = op_readpci(); + abs.h = op_readpci(); +L rd = op_read(abs.w); + call(op); +} + +template +void CPU::opi_read_absolute_x() { + abs.l = op_readpci(); + abs.h = op_readpci(); + op_page(abs.w, abs.w + regs.x); +L rd = op_read(abs.w + regs.x); + call(op); +} + +template +void CPU::opi_read_absolute_y() { + abs.l = op_readpci(); + abs.h = op_readpci(); + op_page(abs.w, abs.w + regs.y); +L rd = op_read(abs.w + regs.y); + call(op); +} + +template +void CPU::opi_read_immediate() { +L rd = op_readpci(); + call(op); +} + +template +void CPU::opi_read_indirect_zero_page_x() { + zp = op_readpci(); + op_readzp(zp); + abs.l = op_readzp(zp++ + regs.x); + abs.h = op_readzp(zp++ + regs.x); +L rd = op_read(abs.w); + call(op); +} + +template +void CPU::opi_read_indirect_zero_page_y() { + rd = op_readpci(); + abs.l = op_readzp(rd++); + abs.h = op_readzp(rd++); + op_page(abs.w, abs.w + regs.y); +L rd = op_read(abs.w + regs.y); + call(op); +} + +template +void CPU::opi_read_zero_page() { + zp = op_readpci(); +L rd = op_readzp(zp); + call(op); +} + +template +void CPU::opi_read_zero_page_x() { + zp = op_readpci(); + op_readzp(zp); +L rd = op_readzp(zp + regs.x); + call(op); +} + +template +void CPU::opi_read_zero_page_y() { + zp = op_readpci(); + op_readzp(zp); +L rd = op_readzp(zp + regs.y); + call(op); +} + +template +void CPU::opi_rmw_absolute() { + abs.l = op_readpci(); + abs.h = op_readpci(); + rd = op_read(abs.w); + op_write(abs.w, rd); + call(op); +L op_write(abs.w, rd); +} + +template +void CPU::opi_rmw_absolute_x() { + abs.l = op_readpci(); + abs.h = op_readpci(); + op_page_always(abs.w, abs.w + regs.x); + rd = op_read(abs.w + regs.x); + op_write(abs.w + regs.x, rd); + call(op); +L op_write(abs.w + regs.x, rd); +} + +template +void CPU::opi_rmw_zero_page() { + zp = op_readpci(); + rd = op_readzp(zp); + op_writezp(zp, rd); + call(op); +L op_writezp(zp, rd); +} + +template +void CPU::opi_rmw_zero_page_x() { + zp = op_readpci(); + op_readzp(zp); + rd = op_readzp(zp + regs.x); + op_writezp(zp + regs.x, rd); + call(op); +L op_writezp(zp + regs.x, rd); +} + +void CPU::opi_set_flag(bool &flag) { +L op_readpc(); + flag = 1; +} + +template +void CPU::opi_shift() { +L op_readpc(); + call(op); +} + +void CPU::opi_store_absolute(uint8 &r) { + abs.l = op_readpci(); + abs.h = op_readpci(); +L op_write(abs.w, r); +} + +void CPU::opi_store_absolute_x(uint8 &r) { + abs.l = op_readpci(); + abs.h = op_readpci(); + op_page_always(abs.w, abs.w + regs.x); +L op_write(abs.w + regs.x, r); +} + +void CPU::opi_store_absolute_y(uint8 &r) { + abs.l = op_readpci(); + abs.h = op_readpci(); + op_page_always(abs.w, abs.w + regs.y); +L op_write(abs.w + regs.y, r); +} + +void CPU::opi_store_indirect_zero_page_x(uint8 &r) { + zp = op_readpci(); + op_readzp(zp); + abs.l = op_readzp(zp++ + regs.x); + abs.h = op_readzp(zp++ + regs.x); +L op_write(abs.w, r); +} + +void CPU::opi_store_indirect_zero_page_y(uint8 &r) { + rd = op_readpci(); + abs.l = op_readzp(rd++); + abs.h = op_readzp(rd++); + op_page_always(abs.w, abs.w + regs.y); +L op_write(abs.w + regs.y, r); +} + +void CPU::opi_store_zero_page(uint8 &r) { + zp = op_readpci(); +L op_writezp(zp, r); +} + +void CPU::opi_store_zero_page_x(uint8 &r) { + zp = op_readpci(); + op_readzp(zp); +L op_writezp(zp + regs.x, r); +} + +void CPU::opi_store_zero_page_y(uint8 &r) { + zp = op_readpci(); + op_readzp(zp); +L op_writezp(zp + regs.y, r); +} + +void CPU::opi_transfer(uint8 &s, uint8 &d, bool flag) { +L op_readpc(); + d = s; + if(flag == false) return; + regs.p.n = (d & 0x80); + regs.p.z = (d == 0); +} + +//opcodes +//======= + +void CPU::op_brk() { + op_readpci(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + op_writesp(regs.p | 0x30); + abs.l = op_read(0xfffe); + regs.p.i = 1; + regs.p.d = 0; +L abs.h = op_read(0xffff); + regs.pc = abs.w; +} + +void CPU::op_jmp_absolute() { + abs.l = op_readpci(); +L abs.h = op_readpci(); + regs.pc = abs.w; +} + +void CPU::op_jmp_indirect_absolute() { + abs.l = op_readpci(); + abs.h = op_readpci(); + iabs.l = op_read(abs.w); abs.l++; +L iabs.h = op_read(abs.w); abs.l++; + regs.pc = iabs.w; +} + +void CPU::op_jsr_absolute() { + abs.l = op_readpci(); + abs.h = op_readpci(); + op_readpc(); + regs.pc--; + op_writesp(regs.pc >> 8); +L op_writesp(regs.pc >> 0); + regs.pc = abs.w; +} + +void CPU::op_nop() { +L op_readpc(); +} + +void CPU::op_php() { + op_readpc(); +L op_writesp(regs.p | 0x30); +} + +void CPU::op_plp() { + op_readpc(); + op_readpc(); +L regs.p = op_readsp(); +} + +void CPU::op_rti() { + op_readpc(); + op_readpc(); + regs.p = op_readsp(); + abs.l = op_readsp(); +L abs.h = op_readsp(); + regs.pc = abs.w; +} + +void CPU::op_rts() { + op_readpc(); + op_readpc(); + abs.l = op_readsp(); + abs.h = op_readsp(); +L op_readpc(); + regs.pc = ++abs.w; +} + +//illegal opcodes +//=============== + +void CPU::opill_arr_immediate() { +L rd = op_readpci(); + regs.a &= rd; + regs.a = (regs.p.c << 7) | (regs.a >> 1); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); + regs.p.c = (regs.a & 0x40); + regs.p.v = regs.p.c ^ ((regs.a >> 5) & 1); +} + +void CPU::opill_nop_absolute() { + abs.l = op_readpci(); + abs.h = op_readpci(); +L op_readpc(); +} + +void CPU::opill_nop_absolute_x() { + abs.l = op_readpci(); + abs.h = op_readpci(); + op_page(abs.w, abs.w + regs.x); +L op_readpc(); +} + +void CPU::opill_nop_immediate() { +L rd = op_readpc(); +} + +void CPU::opill_nop_implied() { +L op_readpc(); +} + +void CPU::opill_nop_zero_page() { + zp = op_readpci(); +L op_readzp(zp); +} + +void CPU::opill_nop_zero_page_x() { + zp = op_readpci(); + op_readzp(zp); +L op_readzp(zp + regs.x); +} diff --git a/nes/cpu/cpu.cpp b/nes/cpu/cpu.cpp new file mode 100755 index 00000000..efd7579e --- /dev/null +++ b/nes/cpu/cpu.cpp @@ -0,0 +1,142 @@ +#include + +namespace NES { + +#include "core/core.cpp" +#include "memory/memory.cpp" +#include "serialization.cpp" +CPU cpu; + +void CPU::Main() { + cpu.main(); +} + +void CPU::main() { +//trace = true; +//FILE *fp = fopen("/home/byuu/Desktop/log.txt", "wb"); + + unsigned lpc = 0xffff; + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(status.interrupt_pending) { + interrupt(); + continue; + } + + if(trace) { + if(lpc != regs.pc) { print(disassemble(), "\n"); } lpc = regs.pc; + //if(lpc != regs.pc) { fprintf(fp, "%s\n", (const char*)disassemble()); fflush(fp); } lpc = regs.pc; + } + + op_exec(); + } +} + +void CPU::add_clocks(unsigned clocks) { + apu.clock -= clocks; + if(apu.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(apu.thread); + + ppu.clock -= clocks; + if(ppu.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(ppu.thread); + + cartridge.clock -= clocks; + if(cartridge.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cartridge.thread); +} + +void CPU::power() { + regs.a = 0x00; + regs.x = 0x00; + regs.y = 0x00; + regs.s = 0x00; + regs.p = 0x04; + + for(unsigned addr = 0; addr < 0x0800; addr++) ram[addr] = 0xff; + ram[0x0008] = 0xf7; + ram[0x0009] = 0xef; + ram[0x000a] = 0xdf; + ram[0x000f] = 0xbf; +} + +void CPU::reset() { + Processor::create(CPU::Main, 21477272); + + regs.mdr = 0x00; + regs.s -= 3; + regs.p.i = 1; + + regs.pc = bus.read(0xfffc) << 0; + regs.pc |= bus.read(0xfffd) << 8; + + status.interrupt_pending = false; + status.nmi_pending = false; + status.nmi_line = 0; + status.irq_line = 0; + status.irq_apu_line = 0; + + status.rdy_line = 1; + status.rdy_addr = { false, 0x0000 }; + + status.oam_dma_pending = false; + status.oam_dma_page = 0x00; + + status.controller_latch = false; + status.controller_port0 = 0; + status.controller_port1 = 0; +} + +uint8 CPU::mdr() const { + return regs.mdr; +} + +void CPU::set_rdy_line(bool line) { + status.rdy_line = line; +} + +void CPU::set_rdy_addr(optional addr) { + status.rdy_addr = addr; +} + +uint8 CPU::ram_read(uint16 addr) { + return ram[addr & 0x07ff]; +} + +void CPU::ram_write(uint16 addr, uint8 data) { + ram[addr & 0x07ff] = data; +} + +uint8 CPU::read(uint16 addr) { + if(addr == 0x4016) { + return (mdr() & 0xc0) | input.data(0); + } + + if(addr == 0x4017) { + return (mdr() & 0xc0) | input.data(1); + } + + return apu.read(addr); +} + +void CPU::write(uint16 addr, uint8 data) { + if(addr == 0x4014) { + status.oam_dma_page = data; + status.oam_dma_pending = true; + } + + if(addr == 0x4016) { + input.latch(data & 0x01); + } + + return apu.write(addr, data); +} + +void CPU::oam_dma() { + for(unsigned n = 0; n < 256; n++) { + uint8 data = op_read((status.oam_dma_page << 8) + n); + op_write(0x2004, data); + } +} + +} diff --git a/nes/cpu/cpu.hpp b/nes/cpu/cpu.hpp new file mode 100755 index 00000000..9549aeaa --- /dev/null +++ b/nes/cpu/cpu.hpp @@ -0,0 +1,49 @@ +struct CPU : Processor { + #include "core/core.hpp" + #include "memory/memory.hpp" + uint8 ram[0x0800]; + + struct Status { + bool interrupt_pending; + bool nmi_pending; + bool nmi_line; + bool irq_line; + bool irq_apu_line; + + bool rdy_line; + optional rdy_addr; + + bool oam_dma_pending; + uint8 oam_dma_page; + + bool controller_latch; + unsigned controller_port0; + unsigned controller_port1; + } status; + + static void Main(); + void main(); + void add_clocks(unsigned clocks); + + void power(); + void reset(); + + uint8 mdr() const; + void set_rdy_line(bool); + void set_rdy_addr(optional); + + uint8 ram_read(uint16 addr); + void ram_write(uint16 addr, uint8 data); + + uint8 read(uint16 addr); + void write(uint16 addr, uint8 data); + + void oam_dma(); + + void serialize(serializer&); + +//internal: + bool trace; +}; + +extern CPU cpu; diff --git a/nes/cpu/memory/memory.cpp b/nes/cpu/memory/memory.cpp new file mode 100755 index 00000000..3192edd9 --- /dev/null +++ b/nes/cpu/memory/memory.cpp @@ -0,0 +1,59 @@ +uint8 CPU::op_read(uint16 addr) { + if(status.oam_dma_pending) { + status.oam_dma_pending = false; + op_read(addr); + oam_dma(); + } + + while(status.rdy_line == 0) { + regs.mdr = bus.read(status.rdy_addr ? status.rdy_addr() : addr); + add_clocks(12); + } + + regs.mdr = bus.read(addr); + add_clocks(12); + return regs.mdr; +} + +void CPU::op_write(uint16 addr, uint8 data) { + bus.write(addr, regs.mdr = data); + add_clocks(12); +} + +// + +uint8 CPU::op_readpc() { + return op_read(regs.pc); +} + +uint8 CPU::op_readpci() { + return op_read(regs.pc++); +} + +uint8 CPU::op_readsp() { + return op_read(0x0100 | ++regs.s); +} + +uint8 CPU::op_readzp(uint8 addr) { + return op_read(addr); +} + +// + +void CPU::op_writesp(uint8 data) { + op_write(0x0100 | regs.s--, data); +} + +void CPU::op_writezp(uint8 addr, uint8 data) { + op_write(addr, data); +} + +// + +void CPU::op_page(uint16 x, uint16 y) { + if((x & 0xff00) != (y & 0xff00)) op_read((x & 0xff00) | (y & 0x00ff)); +} + +void CPU::op_page_always(uint16 x, uint16 y) { + op_read((x & 0xff00) | (y & 0x00ff)); +} diff --git a/nes/cpu/memory/memory.hpp b/nes/cpu/memory/memory.hpp new file mode 100755 index 00000000..5edcfe42 --- /dev/null +++ b/nes/cpu/memory/memory.hpp @@ -0,0 +1,13 @@ +uint8 op_read(uint16 addr); +void op_write(uint16 addr, uint8 data); + +uint8 op_readpc(); +uint8 op_readpci(); +uint8 op_readsp(); +uint8 op_readzp(uint8 addr); + +void op_writesp(uint8 data); +void op_writezp(uint8 addr, uint8 data); + +void op_page(uint16 x, uint16 y); +void op_page_always(uint16 x, uint16 y); diff --git a/nes/cpu/serialization.cpp b/nes/cpu/serialization.cpp new file mode 100755 index 00000000..5d9a49d1 --- /dev/null +++ b/nes/cpu/serialization.cpp @@ -0,0 +1,41 @@ +void CPU::serialize(serializer &s) { + Processor::serialize(s); + + s.array(ram); + + s.integer(regs.mdr); + s.integer(regs.pc); + s.integer(regs.a); + s.integer(regs.x); + s.integer(regs.y); + s.integer(regs.s); + s.integer(regs.p.n); + s.integer(regs.p.v); + s.integer(regs.p.d); + s.integer(regs.p.i); + s.integer(regs.p.z); + s.integer(regs.p.c); + + s.integer(abs.w); + s.integer(iabs.w); + s.integer(rd); + s.integer(zp); + s.integer(aa); + + s.integer(status.interrupt_pending); + s.integer(status.nmi_pending); + s.integer(status.nmi_line); + s.integer(status.irq_line); + s.integer(status.irq_apu_line); + + s.integer(status.rdy_line); + s.integer(status.rdy_addr.valid); + s.integer(status.rdy_addr.value); + + s.integer(status.oam_dma_pending); + s.integer(status.oam_dma_page); + + s.integer(status.controller_latch); + s.integer(status.controller_port0); + s.integer(status.controller_port1); +} diff --git a/nes/input/input.cpp b/nes/input/input.cpp new file mode 100755 index 00000000..d85fc93d --- /dev/null +++ b/nes/input/input.cpp @@ -0,0 +1,54 @@ +#include + +namespace NES { + +#include "serialization.cpp" +Input input; + +void Input::latch(bool data) { + latchdata = data; + + if(latchdata == 1) { + counter1 = 0; + counter2 = 0; + } +} + +bool Input::data(bool port) { + bool result = 0; + + if(port == 0) { + if(port1 == Device::Joypad) { + if(counter1 >= 8) return 1; + result = interface->inputPoll(0, 0u, counter1); + if(latchdata == 0) counter1++; + } + } + + if(port == 1) { + if(port2 == Device::Joypad) { + if(counter2 >= 8) return 1; + result = interface->inputPoll(1, 0u, counter2); + if(latchdata == 0) counter2++; + } + } + + return result; +} + +void Input::connect(bool port, Device device) { + if(port == 0) port1 = device, counter1 = 0; + if(port == 1) port2 = device, counter2 = 0; +} + +void Input::power() { + reset(); +} + +void Input::reset() { + latchdata = 0; + counter1 = 0; + counter2 = 0; +} + +} diff --git a/nes/input/input.hpp b/nes/input/input.hpp new file mode 100755 index 00000000..1b1b0dc9 --- /dev/null +++ b/nes/input/input.hpp @@ -0,0 +1,25 @@ +struct Input { + enum class Device : unsigned { + None, + Joypad, + }; + + void latch(bool data); + bool data(bool port); + void connect(bool port, Device device); + + void power(); + void reset(); + + void serialize(serializer &s); + +private: + Device port1; + Device port2; + + bool latchdata; + unsigned counter1; + unsigned counter2; +}; + +extern Input input; diff --git a/nes/input/serialization.cpp b/nes/input/serialization.cpp new file mode 100755 index 00000000..481bf81c --- /dev/null +++ b/nes/input/serialization.cpp @@ -0,0 +1,8 @@ +void Input::serialize(serializer &s) { + s.integer((unsigned&)port1); + s.integer((unsigned&)port2); + + s.integer(latchdata); + s.integer(counter1); + s.integer(counter2); +} diff --git a/nes/interface/interface.cpp b/nes/interface/interface.cpp new file mode 100755 index 00000000..062ad7c8 --- /dev/null +++ b/nes/interface/interface.cpp @@ -0,0 +1,21 @@ +#include + +namespace NES { + +Interface *interface = nullptr; + +void Interface::videoRefresh(const uint16_t *data) { +} + +void Interface::audioSample(const int16_t sample) { +} + +int16_t Interface::inputPoll(bool port, unsigned device, unsigned id) { + return 0; +} + +void Interface::message(const string &text) { + print(text, "\n"); +} + +} diff --git a/nes/interface/interface.hpp b/nes/interface/interface.hpp new file mode 100755 index 00000000..a53af4df --- /dev/null +++ b/nes/interface/interface.hpp @@ -0,0 +1,9 @@ +struct Interface { + virtual void videoRefresh(const uint16_t *data); + virtual void audioSample(int16_t sample); + virtual int16_t inputPoll(bool port, unsigned device, unsigned id); + + virtual void message(const string &text); +}; + +extern Interface *interface; diff --git a/nes/memory/memory.cpp b/nes/memory/memory.cpp new file mode 100755 index 00000000..c158a232 --- /dev/null +++ b/nes/memory/memory.cpp @@ -0,0 +1,41 @@ +#include + +namespace NES { + +Bus bus; + +//$0000-07ff = RAM (2KB) +//$0800-1fff = RAM (mirror) +//$2000-2007 = PPU +//$2008-3fff = PPU (mirror) +//$4000-4017 = APU + I/O +//$4018-ffff = Cartridge + +uint8 Bus::read(uint16 addr) { + uint8 data = cartridge.prg_read(addr); + if(addr <= 0x1fff) data = cpu.ram_read(addr); + else if(addr <= 0x3fff) data = ppu.read(addr); + else if(addr <= 0x4017) data = cpu.read(addr); + + if(cheat.override[addr]) { + for(unsigned n = 0; n < cheat.size(); n++) { + if(cheat[n].addr == addr) { + if(cheat[n].comp > 255 || cheat[n].comp == data) { + data = cheat[n].data; + break; + } + } + } + } + + return data; +} + +void Bus::write(uint16 addr, uint8 data) { + cartridge.prg_write(addr, data); + if(addr <= 0x1fff) return cpu.ram_write(addr, data); + if(addr <= 0x3fff) return ppu.write(addr, data); + if(addr <= 0x4017) return cpu.write(addr, data); +} + +} diff --git a/nes/memory/memory.hpp b/nes/memory/memory.hpp new file mode 100755 index 00000000..6ee5a463 --- /dev/null +++ b/nes/memory/memory.hpp @@ -0,0 +1,6 @@ +struct Bus { + uint8 read(uint16 addr); + void write(uint16 addr, uint8 data); +}; + +extern Bus bus; diff --git a/nes/nes.hpp b/nes/nes.hpp new file mode 100755 index 00000000..7e5d0627 --- /dev/null +++ b/nes/nes.hpp @@ -0,0 +1,118 @@ +#ifndef NES_HPP +#define NES_HPP + +namespace NES { + namespace Info { + static const char Name[] = "bnes"; + static const unsigned SerializerVersion = 1; + } +} + +/* + bnes - NES emulator + authors: byuu, Ryphecha + license: GPLv3 + project started: 2011-09-05 +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace nall; + +namespace NES { + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + + typedef uint_t< 1> uint1; + typedef uint_t< 2> uint2; + typedef uint_t< 3> uint3; + typedef uint_t< 4> uint4; + typedef uint_t< 5> uint5; + typedef uint_t< 6> uint6; + typedef uint_t< 7> uint7; + typedef uint8_t uint8; + + typedef uint_t< 9> uint9; + typedef uint_t<10> uint10; + typedef uint_t<11> uint11; + typedef uint_t<12> uint12; + typedef uint_t<13> uint13; + typedef uint_t<14> uint14; + typedef uint_t<15> uint15; + typedef uint16_t uint16; + + typedef uint_t<17> uint17; + typedef uint_t<18> uint18; + typedef uint_t<19> uint19; + typedef uint_t<20> uint20; + typedef uint_t<21> uint21; + typedef uint_t<22> uint22; + typedef uint_t<23> uint23; + typedef uint_t<24> uint24; + typedef uint_t<25> uint25; + typedef uint_t<26> uint26; + typedef uint_t<27> uint27; + typedef uint_t<28> uint28; + typedef uint_t<29> uint29; + typedef uint_t<30> uint30; + typedef uint_t<31> uint31; + typedef uint32_t uint32; + + typedef uint64_t uint64; + + struct Processor { + cothread_t thread; + unsigned frequency; + int64 clock; + + inline void create(void (*entrypoint)(), unsigned frequency) { + if(thread) co_delete(thread); + thread = co_create(65536 * sizeof(void*), entrypoint); + this->frequency = frequency; + clock = 0; + } + + inline void serialize(serializer &s) { + s.integer(frequency); + s.integer(clock); + } + + inline Processor() : thread(nullptr) { + } + + inline ~Processor() { + if(thread) co_delete(thread); + } + }; + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +} + +#endif diff --git a/nes/ppu/ppu.cpp b/nes/ppu/ppu.cpp new file mode 100755 index 00000000..7f85f1b0 --- /dev/null +++ b/nes/ppu/ppu.cpp @@ -0,0 +1,488 @@ +#include + +namespace NES { + +#include "serialization.cpp" +PPU ppu; + +void PPU::Main() { + ppu.main(); +} + +void PPU::main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::PPU) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + raster_scanline(); + } +} + +void PPU::tick() { + if(status.ly == 240 && status.lx == 340) status.nmi_hold = 1; + if(status.ly == 241 && status.lx == 0) status.nmi_flag = status.nmi_hold; + if(status.ly == 241 && status.lx == 2) cpu.set_nmi_line(status.nmi_enable && status.nmi_flag); + + if(status.ly == 260 && status.lx == 340) status.sprite_zero_hit = 0, status.sprite_overflow = 0; + + if(status.ly == 260 && status.lx == 340) status.nmi_hold = 0; + if(status.ly == 261 && status.lx == 0) status.nmi_flag = status.nmi_hold; + if(status.ly == 261 && status.lx == 2) cpu.set_nmi_line(status.nmi_enable && status.nmi_flag); + + clock += 4; + if(clock >= 0) co_switch(cpu.thread); + + status.lx++; +} + +void PPU::scanline() { + status.lx = 0; + if(++status.ly == 262) { + status.ly = 0; + frame(); + } + cartridge.scanline(status.ly); +} + +void PPU::frame() { + status.field ^= 1; + interface->videoRefresh(buffer); + scheduler.exit(Scheduler::ExitReason::FrameEvent); +} + +void PPU::power() { +} + +void PPU::reset() { + create(PPU::Main, 21477272); + + status.mdr = 0x00; + status.field = 0; + status.ly = 0; + status.bus_data = 0x00; + status.address_latch = 0; + + status.vaddr = 0x0000; + status.taddr = 0x0000; + status.xaddr = 0x00; + + status.nmi_hold = 0; + status.nmi_flag = 0; + + //$2000 + status.nmi_enable = false; + status.master_select = 0; + status.sprite_size = 0; + status.bg_addr = 0x0000; + status.sprite_addr = 0x0000; + status.vram_increment = 1; + + //$2001 + status.emphasis = 0; + status.sprite_enable = false; + status.bg_enable = false; + status.sprite_edge_enable = false; + status.bg_edge_enable = false; + status.grayscale = false; + + //$2002 + status.sprite_zero_hit = false; + status.sprite_overflow = false; + + //$2003 + status.oam_addr = 0x00; + + for(auto &n : buffer) n = 0; + for(auto &n : ciram ) n = 0; + for(auto &n : cgram ) n = 0; + for(auto &n : oam ) n = 0; +} + +uint8 PPU::read(uint16 addr) { + uint8 result = 0x00; + + switch(addr & 7) { + case 2: //PPUSTATUS + result |= status.nmi_flag << 7; + result |= status.sprite_zero_hit << 6; + result |= status.sprite_overflow << 5; + result |= status.mdr & 0x1f; + status.address_latch = 0; + status.nmi_hold = 0; + cpu.set_nmi_line(status.nmi_flag = 0); + break; + case 4: //OAMDATA + result = oam[status.oam_addr]; + if((status.oam_addr & 3) == 3) result &= 0xe3; + break; + case 7: //PPUDATA + if(raster_enable() && (status.ly <= 240 || status.ly == 261)) return 0x00; + + addr = status.vaddr & 0x3fff; + if(addr <= 0x1fff) { + result = status.bus_data; + status.bus_data = cartridge.chr_read(addr); + } else if(addr <= 0x3eff) { + result = status.bus_data; + status.bus_data = cartridge.chr_read(addr); + } else if(addr <= 0x3fff) { + result = cgram_read(addr); + status.bus_data = cartridge.chr_read(addr); + } + status.vaddr += status.vram_increment; + break; + } + + return result; +} + +void PPU::write(uint16 addr, uint8 data) { + status.mdr = data; + + switch(addr & 7) { + case 0: //PPUCTRL + status.nmi_enable = data & 0x80; + status.master_select = data & 0x40; + status.sprite_size = data & 0x20; + status.bg_addr = (data & 0x10) ? 0x1000 : 0x0000; + status.sprite_addr = (data & 0x08) ? 0x1000 : 0x0000; + status.vram_increment = (data & 0x04) ? 32 : 1; + status.taddr = (status.taddr & 0x73ff) | ((data & 0x03) << 10); + cpu.set_nmi_line(status.nmi_enable && status.nmi_hold && status.nmi_flag); + return; + case 1: //PPUMASK + status.emphasis = data >> 5; + status.sprite_enable = data & 0x10; + status.bg_enable = data & 0x08; + status.sprite_edge_enable = data & 0x04; + status.bg_edge_enable = data & 0x02; + status.grayscale = data & 0x01; + return; + case 2: //PPUSTATUS + return; + case 3: //OAMADDR + status.oam_addr = data; + return; + case 4: //OAMDATA + oam[status.oam_addr++] = data; + return; + case 5: //PPUSCROLL + if(status.address_latch == 0) { + status.xaddr = data & 0x07; + status.taddr = (status.taddr & 0x7fe0) | (data >> 3); + } else { + status.taddr = (status.taddr & 0x0c1f) | ((data & 0x07) << 12) | ((data >> 3) << 5); + } + status.address_latch ^= 1; + return; + case 6: //PPUADDR + if(status.address_latch == 0) { + status.taddr = (status.taddr & 0x00ff) | ((data & 0x3f) << 8); + } else { + status.taddr = (status.taddr & 0x7f00) | data; + status.vaddr = status.taddr; + } + status.address_latch ^= 1; + return; + case 7: //PPUDATA + if(raster_enable() && (status.ly <= 240 || status.ly == 261)) return; + + addr = status.vaddr & 0x3fff; + if(addr <= 0x1fff) { + cartridge.chr_write(addr, data); + } else if(addr <= 0x3eff) { + cartridge.chr_write(addr, data); + } else if(addr <= 0x3fff) { + cgram_write(addr, data); + } + status.vaddr += status.vram_increment; + return; + } +} + +uint8 PPU::ciram_read(uint16 addr) { + return ciram[addr & 0x07ff]; +} + +void PPU::ciram_write(uint16 addr, uint8 data) { + ciram[addr & 0x07ff] = data; +} + +uint8 PPU::cgram_read(uint16 addr) { + if((addr & 0x13) == 0x10) addr &= ~0x10; + uint8 data = cgram[addr & 0x1f]; + if(status.grayscale) data &= 0x30; + return data; +} + +void PPU::cgram_write(uint16 addr, uint8 data) { + if((addr & 0x13) == 0x10) addr &= ~0x10; + cgram[addr & 0x1f] = data; +} + +// + +//vaddr = 0yyy VHYY YYYX XXXX +//yyy = fine Yscroll (y:d0-d2) +//V = V nametable (y:d8) +//H = H nametable (x:d8) +//YYYYY = Y nametable (y:d3-d7) +//XXXXX = X nametable (x:d3-d7) + +bool PPU::raster_enable() const { + return (status.bg_enable || status.sprite_enable); +} + +unsigned PPU::nametable_addr() const { + return 0x2000 + (status.vaddr & 0x0c00); +} + +unsigned PPU::scrollx() const { + return ((status.vaddr & 0x1f) << 3) | status.xaddr; +} + +unsigned PPU::scrolly() const { + return (((status.vaddr >> 5) & 0x1f) << 3) | ((status.vaddr >> 12) & 7); +} + +unsigned PPU::sprite_height() const { + return status.sprite_size == 0 ? 8 : 16; +} + +// + +uint8 PPU::chr_load(uint16 addr) { + if(raster_enable() == false) return 0x00; + return cartridge.chr_read(addr); +} + +// + +void PPU::scrollx_increment() { + if(raster_enable() == false) return; + status.vaddr = (status.vaddr & 0x7fe0) | ((status.vaddr + 0x0001) & 0x001f); + if((status.vaddr & 0x001f) == 0x0000) { + status.vaddr ^= 0x0400; + } +} + +void PPU::scrolly_increment() { + if(raster_enable() == false) return; + status.vaddr = (status.vaddr & 0x0fff) | ((status.vaddr + 0x1000) & 0x7000); + if((status.vaddr & 0x7000) == 0x0000) { + status.vaddr = (status.vaddr & 0x7c1f) | ((status.vaddr + 0x0020) & 0x03e0); + if((status.vaddr & 0x03e0) == 0x03c0) { //0x03c0 == 30 << 5; 30 * 8 = 240 + status.vaddr &= 0x7c1f; + status.vaddr ^= 0x0800; + } + } +} + +// + +void PPU::raster_pixel() { + uint16 *output = buffer + status.ly * 256; + + unsigned mask = 0x8000 >> (status.xaddr + (status.lx & 7)); + unsigned palette = 0, object_palette = 0; + bool object_priority = 0; + palette |= (raster.tiledatalo & mask) ? 1 : 0; + palette |= (raster.tiledatahi & mask) ? 2 : 0; + if(palette) { + unsigned attr = raster.attribute; + if(mask >= 256) attr >>= 2; + palette |= (attr & 3) << 2; + } + + if(status.bg_enable == false) palette = 0; + if(status.bg_edge_enable == false && status.lx < 8) palette = 0; + + if(status.sprite_enable == true) + for(signed sprite = 7; sprite >= 0; sprite--) { + if(status.sprite_edge_enable == false && status.lx < 8) continue; + if(raster.oam[sprite].id == 64) continue; + + unsigned spritex = status.lx - raster.oam[sprite].x; + if(spritex >= 8) continue; + + if(raster.oam[sprite].attr & 0x40) spritex ^= 7; + unsigned mask = 0x80 >> spritex; + unsigned sprite_palette = 0; + sprite_palette |= (raster.oam[sprite].tiledatalo & mask) ? 1 : 0; + sprite_palette |= (raster.oam[sprite].tiledatahi & mask) ? 2 : 0; + if(sprite_palette == 0) continue; + + if(raster.oam[sprite].id == 0 && palette && status.lx != 255) status.sprite_zero_hit = 1; + sprite_palette |= (raster.oam[sprite].attr & 3) << 2; + + object_priority = raster.oam[sprite].attr & 0x20; + object_palette = 16 + sprite_palette; + } + + if(object_palette) { + if(palette == 0 || object_priority == 0) palette = object_palette; + } + + if(raster_enable() == false) palette = 0; + output[status.lx] = (status.emphasis << 6) | cgram_read(palette); +} + +void PPU::raster_sprite() { + if(raster_enable() == false) return; + + unsigned n = raster.oam_iterator++; + signed ly = (status.ly == 261 ? -1 : status.ly); + unsigned y = ly - oam[(n * 4) + 0]; + + if(y >= sprite_height()) return; + if(raster.oam_counter == 8) { + status.sprite_overflow = 1; + return; + } + + raster.soam[raster.oam_counter].id = n; + raster.soam[raster.oam_counter].y = oam[(n * 4) + 0]; + raster.soam[raster.oam_counter].tile = oam[(n * 4) + 1]; + raster.soam[raster.oam_counter].attr = oam[(n * 4) + 2]; + raster.soam[raster.oam_counter].x = oam[(n * 4) + 3]; + raster.oam_counter++; +} + +void PPU::raster_scanline() { + if((status.ly >= 240 && status.ly <= 260)) { + for(unsigned x = 0; x < 341; x++) tick(); + return scanline(); + } + + raster.oam_iterator = 0; + raster.oam_counter = 0; + + for(unsigned n = 0; n < 8; n++) { + raster.soam[n].id = 64; + raster.soam[n].y = 0xff; + raster.soam[n].tile = 0xff; + raster.soam[n].attr = 0xff; + raster.soam[n].x = 0xff; + raster.soam[n].tiledatalo = 0; + raster.soam[n].tiledatahi = 0; + } + + for(unsigned tile = 0; tile < 32; tile++) { // 0-255 + unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff)); + unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7); + raster_pixel(); + tick(); + + raster_pixel(); + tick(); + + unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5)); + if(scrolly() & 16) attribute >>= 4; + if(scrollx() & 16) attribute >>= 2; + raster_pixel(); + tick(); + + scrollx_increment(); + if(tile == 31) scrolly_increment(); + raster_pixel(); + raster_sprite(); + tick(); + + unsigned tiledatalo = chr_load(tileaddr + 0); + raster_pixel(); + tick(); + + raster_pixel(); + tick(); + + unsigned tiledatahi = chr_load(tileaddr + 8); + raster_pixel(); + tick(); + + raster_pixel(); + raster_sprite(); + tick(); + + raster.nametable = (raster.nametable << 8) | nametable; + raster.attribute = (raster.attribute << 2) | (attribute & 3); + raster.tiledatalo = (raster.tiledatalo << 8) | tiledatalo; + raster.tiledatahi = (raster.tiledatahi << 8) | tiledatahi; + } + + for(unsigned n = 0; n < 8; n++) raster.oam[n] = raster.soam[n]; + + for(unsigned sprite = 0; sprite < 8; sprite++) { //256-319 + unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff)); + tick(); + + if(raster_enable() && sprite == 0) status.vaddr = (status.vaddr & 0x7be0) | (status.taddr & 0x041f); //257 + tick(); + + unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5)); + unsigned tileaddr = (sprite_height() == 8) + ? status.sprite_addr + raster.oam[sprite].tile * 16 + : ((raster.oam[sprite].tile & ~1) * 16) + ((raster.oam[sprite].tile & 1) * 0x1000); + tick(); + tick(); + + unsigned spritey = (status.ly - raster.oam[sprite].y) & (sprite_height() - 1); + if(raster.oam[sprite].attr & 0x80) spritey ^= (sprite_height() - 1); + tileaddr += spritey + (spritey & 8); + + raster.oam[sprite].tiledatalo = chr_load(tileaddr + 0); + tick(); + tick(); + + raster.oam[sprite].tiledatahi = chr_load(tileaddr + 8); + tick(); + tick(); + + if(raster_enable() && sprite == 6 && status.ly == 261) status.vaddr = status.taddr; //304 + } + + for(unsigned tile = 0; tile < 2; tile++) { //320-335 + unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff)); + unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7); + tick(); + tick(); + + unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5)); + if(scrolly() & 16) attribute >>= 4; + if(scrollx() & 16) attribute >>= 2; + tick(); + + scrollx_increment(); + tick(); + + unsigned tiledatalo = chr_load(tileaddr + 0); + tick(); + tick(); + + unsigned tiledatahi = chr_load(tileaddr + 8); + tick(); + tick(); + + raster.nametable = (raster.nametable << 8) | nametable; + raster.attribute = (raster.attribute << 2) | (attribute & 3); + raster.tiledatalo = (raster.tiledatalo << 8) | tiledatalo; + raster.tiledatahi = (raster.tiledatahi << 8) | tiledatahi; + } + + //336-339 + chr_load(0x2000 | (status.vaddr & 0x0fff)); + tick(); + bool skip = (raster_enable() && status.field == 1 && status.ly == 261); + tick(); + + chr_load(0x2000 | (status.vaddr & 0x0fff)); + tick(); + tick(); + + //340 + if(skip == false) tick(); + + return scanline(); +} + +} diff --git a/nes/ppu/ppu.hpp b/nes/ppu/ppu.hpp new file mode 100755 index 00000000..24ebdcbd --- /dev/null +++ b/nes/ppu/ppu.hpp @@ -0,0 +1,107 @@ +struct PPU : Processor { + static void Main(); + void main(); + void tick(); + + void scanline(); + void frame(); + + void power(); + void reset(); + + uint8 read(uint16 addr); + void write(uint16 addr, uint8 data); + + uint8 ciram_read(uint16 addr); + void ciram_write(uint16 addr, uint8 data); + + uint8 cgram_read(uint16 addr); + void cgram_write(uint16 addr, uint8 data); + + bool raster_enable() const; + unsigned nametable_addr() const; + unsigned scrollx() const; + unsigned scrolly() const; + unsigned sprite_height() const; + + uint8 chr_load(uint16 addr); + + void scrollx_increment(); + void scrolly_increment(); + + void raster_pixel(); + void raster_sprite(); + void raster_scanline(); + + void serialize(serializer&); + + struct Status { + uint8 mdr; + + bool field; + unsigned lx; + unsigned ly; + + uint8 bus_data; + + bool address_latch; + + uint15 vaddr; + uint15 taddr; + uint8 xaddr; + + bool nmi_hold; + bool nmi_flag; + + //$2000 + bool nmi_enable; + bool master_select; + bool sprite_size; + unsigned bg_addr; + unsigned sprite_addr; + unsigned vram_increment; + + //$2001 + uint3 emphasis; + bool sprite_enable; + bool bg_enable; + bool sprite_edge_enable; + bool bg_edge_enable; + bool grayscale; + + //$2002 + bool sprite_zero_hit; + bool sprite_overflow; + + //$2003 + uint8 oam_addr; + } status; + + struct Raster { + uint16 nametable; + uint16 attribute; + uint16 tiledatalo; + uint16 tiledatahi; + + unsigned oam_iterator; + unsigned oam_counter; + + struct OAM { + uint8 id; + uint8 y; + uint8 tile; + uint8 attr; + uint8 x; + + uint8 tiledatalo; + uint8 tiledatahi; + } oam[8], soam[8]; + } raster; + + uint16 buffer[256 * 262]; + uint8 ciram[2048]; + uint8 cgram[32]; + uint8 oam[256]; +}; + +extern PPU ppu; diff --git a/nes/ppu/serialization.cpp b/nes/ppu/serialization.cpp new file mode 100755 index 00000000..db4cee1b --- /dev/null +++ b/nes/ppu/serialization.cpp @@ -0,0 +1,74 @@ +void PPU::serialize(serializer &s) { + Processor::serialize(s); + + s.integer(status.mdr); + + s.integer(status.field); + s.integer(status.lx); + s.integer(status.ly); + + s.integer(status.bus_data); + + s.integer(status.address_latch); + + s.integer(status.vaddr); + s.integer(status.taddr); + s.integer(status.xaddr); + + s.integer(status.nmi_hold); + s.integer(status.nmi_flag); + + s.integer(status.nmi_enable); + s.integer(status.master_select); + s.integer(status.sprite_size); + s.integer(status.bg_addr); + s.integer(status.sprite_addr); + s.integer(status.vram_increment); + + s.integer(status.emphasis); + s.integer(status.sprite_enable); + s.integer(status.bg_enable); + s.integer(status.sprite_edge_enable); + s.integer(status.bg_edge_enable); + s.integer(status.grayscale); + + s.integer(status.sprite_zero_hit); + s.integer(status.sprite_overflow); + + s.integer(status.oam_addr); + + s.integer(raster.nametable); + s.integer(raster.attribute); + s.integer(raster.tiledatalo); + s.integer(raster.tiledatahi); + + s.integer(raster.oam_iterator); + s.integer(raster.oam_counter); + + for(unsigned n = 0; n < 8; n++) { + s.integer(raster.oam[n].id); + s.integer(raster.oam[n].y); + s.integer(raster.oam[n].tile); + s.integer(raster.oam[n].attr); + s.integer(raster.oam[n].x); + + s.integer(raster.oam[n].tiledatalo); + s.integer(raster.oam[n].tiledatahi); + } + + for(unsigned n = 0; n < 8; n++) { + s.integer(raster.soam[n].id); + s.integer(raster.soam[n].y); + s.integer(raster.soam[n].tile); + s.integer(raster.soam[n].attr); + s.integer(raster.soam[n].x); + + s.integer(raster.soam[n].tiledatalo); + s.integer(raster.soam[n].tiledatahi); + } + + s.array(buffer); + s.array(ciram); + s.array(cgram); + s.array(oam); +} diff --git a/nes/scheduler/scheduler.cpp b/nes/scheduler/scheduler.cpp new file mode 100755 index 00000000..eca5857d --- /dev/null +++ b/nes/scheduler/scheduler.cpp @@ -0,0 +1,29 @@ +#include + +namespace NES { + +Scheduler scheduler; + +void Scheduler::enter() { + host_thread = co_active(); + co_switch(thread); +} + +void Scheduler::exit(ExitReason reason) { + exit_reason = reason; + thread = co_active(); + co_switch(host_thread); +} + +void Scheduler::power() { + reset(); +} + +void Scheduler::reset() { + host_thread = co_active(); + thread = cpu.thread; + sync = SynchronizeMode::None; + exit_reason = ExitReason::UnknownEvent; +} + +} diff --git a/nes/scheduler/scheduler.hpp b/nes/scheduler/scheduler.hpp new file mode 100755 index 00000000..518a5d45 --- /dev/null +++ b/nes/scheduler/scheduler.hpp @@ -0,0 +1,16 @@ +struct Scheduler : property { + enum class SynchronizeMode : unsigned { None, PPU, All } sync; + enum class ExitReason : unsigned { UnknownEvent, FrameEvent, SynchronizeEvent }; + readonly exit_reason; + + cothread_t host_thread; //program thread (used to exit emulation) + cothread_t thread; //active emulation thread (used to enter emulation) + + void enter(); + void exit(ExitReason); + + void power(); + void reset(); +}; + +extern Scheduler scheduler; diff --git a/nes/system/serialization.cpp b/nes/system/serialization.cpp new file mode 100755 index 00000000..d22ab8f8 --- /dev/null +++ b/nes/system/serialization.cpp @@ -0,0 +1,60 @@ +serializer System::serialize() { + serializer s(serialize_size); + + unsigned signature = 0x31545342, version = Info::SerializerVersion, crc32 = 0; + char description[512]; + memset(&description, 0, sizeof description); + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(description); + + serialize_all(s); + return s; +} + +bool System::unserialize(serializer &s) { + unsigned signature, version, crc32; + char description[512]; + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(description); + + if(signature != 0x31545342) return false; + if(version != Info::SerializerVersion) return false; +//if(crc32 != 0) return false; + + power(); + serialize_all(s); + return true; +} + +void System::serialize(serializer &s) { +} + +void System::serialize_all(serializer &s) { + system.serialize(s); + input.serialize(s); + cartridge.serialize(s); + cpu.serialize(s); + apu.serialize(s); + ppu.serialize(s); +} + +void System::serialize_init() { + serializer s; + + unsigned signature = 0, version = 0, crc32 = 0; + char description[512]; + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(description); + + serialize_all(s); + serialize_size = s.size(); +} diff --git a/nes/system/system.cpp b/nes/system/system.cpp new file mode 100755 index 00000000..6bc0da4f --- /dev/null +++ b/nes/system/system.cpp @@ -0,0 +1,71 @@ +#include + +namespace NES { + +#include "serialization.cpp" +System system; + +void System::run() { + scheduler.enter(); +} + +void System::runtosave() { + scheduler.sync = Scheduler::SynchronizeMode::PPU; + runthreadtosave(); + + scheduler.sync = Scheduler::SynchronizeMode::All; + scheduler.thread = cpu.thread; + runthreadtosave(); + + scheduler.sync = Scheduler::SynchronizeMode::All; + scheduler.thread = apu.thread; + runthreadtosave(); + + scheduler.sync = Scheduler::SynchronizeMode::All; + scheduler.thread = cartridge.thread; + runthreadtosave(); + + scheduler.sync = Scheduler::SynchronizeMode::None; +} + +void System::runthreadtosave() { + while(true) { + scheduler.enter(); + if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break; + if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent); + } +} + +void System::load() { + serialize_init(); +} + +void System::power() { + cartridge.power(); + cpu.power(); + apu.power(); + ppu.power(); + input.reset(); + scheduler.power(); + reset(); +} + +void System::reset() { + cartridge.reset(); + cpu.reset(); + apu.reset(); + ppu.reset(); + input.reset(); + scheduler.reset(); +} + +void System::init() { + assert(interface != 0); + input.connect(0, Input::Device::Joypad); + input.connect(1, Input::Device::None); +} + +void System::term() { +} + +} diff --git a/nes/system/system.hpp b/nes/system/system.hpp new file mode 100755 index 00000000..88b73c57 --- /dev/null +++ b/nes/system/system.hpp @@ -0,0 +1,22 @@ +struct System { + void run(); + void runtosave(); + void runthreadtosave(); + + void load(); + void power(); + void reset(); + + void init(); + void term(); + + serializer serialize(); + bool unserialize(serializer&); + + void serialize(serializer&); + void serialize_all(serializer&); + void serialize_init(); + unsigned serialize_size; +}; + +extern System system; diff --git a/nes/video/video.cpp b/nes/video/video.cpp new file mode 100755 index 00000000..f90626a3 --- /dev/null +++ b/nes/video/video.cpp @@ -0,0 +1,87 @@ +#include + +#define VIDEO_CPP +namespace NES { + +Video video; + +unsigned Video::palette30( + unsigned n, double saturation, double hue, + double contrast, double brightness, double gamma +) { + signed color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1; + + static const double black = 0.518, white = 1.962, attenuation = 0.746; + static const double levels[8] = { + 0.350, 0.518, 0.962, 1.550, + 1.094, 1.506, 1.962, 1.962, + }; + + double lo_and_hi[2] = { + levels[level + 4 * (color == 0x0)], + levels[level + 4 * (color < 0xd)], + }; + + double y = 0.0, i = 0.0, q = 0.0; + auto wave = [](signed p, signed color) { return (color + p + 8) % 12 < 6; }; + for(signed p = 0; p < 12; p++) { + double spot = lo_and_hi[wave(p, color)]; + + if(((n & 0x040) && wave(p, 12)) + || ((n & 0x080) && wave(p, 4)) + || ((n & 0x100) && wave(p, 8)) + ) spot *= attenuation; + + double v = (spot - black) / (white - black); + + v = (v - 0.5) * contrast + 0.5; + v *= brightness / 12.0; + + y += v; + i += v * std::cos((3.141592653 / 6.0) * (p + hue)); + q += v * std::sin((3.141592653 / 6.0) * (p + hue)); + } + + i *= saturation; + q *= saturation; + + auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : std::pow(f, 2.2 / gamma); }; + return (uclamp<10>(1023.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q)) << 20) + + (uclamp<10>(1023.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q)) << 10) + + (uclamp<10>(1023.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q)) << 0); +} + +void Video::generate(Format format) { + for(unsigned n = 0; n < (1 << 9); n++) palette[n] = palette30(n, 2.0, 0.0, 1.0, 1.0, 1.8); + + if(format == Format::RGB24) { + for(unsigned n = 0; n < (1 << 9); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff); + } + } + + if(format == Format::RGB16) { + for(unsigned n = 0; n < (1 << 9); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f); + } + } + + if(format == Format::RGB15) { + for(unsigned n = 0; n < (1 << 9); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f); + } + } +} + +Video::Video() { + palette = new unsigned[1 << 9]; +} + +Video::~Video() { + delete[] palette; +} + +} diff --git a/nes/video/video.hpp b/nes/video/video.hpp new file mode 100755 index 00000000..6fec2bf9 --- /dev/null +++ b/nes/video/video.hpp @@ -0,0 +1,11 @@ +struct Video { + enum class Format : unsigned { RGB30, RGB24, RGB16, RGB15 }; + unsigned *palette; + + unsigned palette30(unsigned, double, double, double, double, double); + void generate(Format format); + Video(); + ~Video(); +}; + +extern Video video; diff --git a/phoenix/core/core.cpp b/phoenix/core/core.cpp new file mode 100755 index 00000000..0426ba10 --- /dev/null +++ b/phoenix/core/core.cpp @@ -0,0 +1,1271 @@ +#include "state.hpp" +#include "layout/fixed-layout.cpp" +#include "layout/horizontal-layout.cpp" +#include "layout/vertical-layout.cpp" + +#if defined(PHOENIX_WINDOWS) + #include "../windows/platform.cpp" +#elif defined(PHOENIX_QT) + #include "../qt/platform.cpp" +#elif defined(PHOENIX_GTK) + #include "../gtk/platform.cpp" +#elif defined(PHOENIX_REFERENCE) + #include "../reference/platform.cpp" +#endif + +static bool OS_quit = false; +Window Window::None; + +//Font +//==== + +Geometry Font::geometry(const string &text) { + return pFont::geometry(description, text); +} + +Font::Font(const string &description): +description(description) { +} + +//Image +//===== + +bool Image::load(const string &filename, const Color &alpha) { + if(data) { delete[] data; data = nullptr; } + + file fp; + if(fp.open(filename, file::mode::read) == false) return false; + uint8_t d0 = fp.read(); + uint8_t d1 = fp.read(); + uint8_t d2 = fp.read(); + uint8_t d3 = fp.read(); + fp.close(); + + if(d0 == 'B' && d1 == 'M') { + bmp::read(filename, data, width, height); + } + + if(d0 == 0x89 && d1 == 'P' && d2 == 'N' && d3 == 'G') { + png image; + if(image.decode(filename)) { + image.alphaTransform((alpha.red << 16) + (alpha.green << 8) + (alpha.blue << 0)); + width = image.info.width, height = image.info.height; + data = new uint32_t[width * height]; + memcpy(data, image.data, width * height * sizeof(uint32_t)); + } + } + + return data; +} + +void Image::load(const uint32_t *data, const Size &size) { + if(data) { delete[] data; data = nullptr; } + width = size.width, height = size.height; + this->data = new uint32_t[width * height]; + memcpy(this->data, data, width * height * sizeof(uint32_t)); +} + +Image& Image::operator=(const Image &source) { + if(this == &source) return *this; + if(data) { delete[] data; data = nullptr; } + if(source.data == nullptr) return *this; + width = source.width, height = source.height; + data = new uint32_t[width * height]; + memcpy(data, source.data, width * height * sizeof(uint32_t)); + return *this; +} + +Image& Image::operator=(Image &&source) { + if(this == &source) return *this; + if(data) { delete[] data; data = nullptr; } + data = source.data, width = source.width, height = source.height; + source.data = nullptr; + return *this; +} + +Image::Image() : data(nullptr) { +} + +Image::Image(const string &filename, const Color &alpha) : data(nullptr) { + load(filename, alpha); +} + +Image::Image(const uint32_t *data, const Size &size) { + load(data, size); +} + +Image::Image(const Image &source) : data(nullptr) { + operator=(source); +} + +Image::Image(Image &&source) : data(nullptr) { + operator=(std::forward(source)); +} + +Image::~Image() { + if(data) delete[] data; +} + +//Object +//====== + +Object::Object(pObject &p): +p(p) { + OS::initialize(); + p.constructor(); +} + +Object::~Object() { + p.destructor(); + delete &p; +} + +//OS +//== + +Geometry OS::availableGeometry() { + return pOS::availableGeometry(); +} + +Geometry OS::desktopGeometry() { + return pOS::desktopGeometry(); +} + +string OS::fileLoad_(Window &parent, const string &path, const lstring &filter_) { + auto filter = filter_; + if(filter.size() == 0) filter.append("All files (*)"); + return pOS::fileLoad(parent, path, filter); +} + +string OS::fileSave_(Window &parent, const string &path, const lstring &filter_) { + auto filter = filter_; + if(filter.size() == 0) filter.append("All files (*)"); + return pOS::fileSave(parent, path, filter); +} + +string OS::folderSelect(Window &parent, const string &path) { + return pOS::folderSelect(parent, path); +} + +void OS::main() { + return pOS::main(); +} + +bool OS::pendingEvents() { + return pOS::pendingEvents(); +} + +void OS::processEvents() { + return pOS::processEvents(); +} + +void OS::quit() { + OS_quit = true; + return pOS::quit(); +} + +void OS::initialize() { + static bool initialized = false; + if(initialized == false) { + initialized = true; + return pOS::initialize(); + } +} + +//Timer +//===== + +void Timer::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} + +void Timer::setInterval(unsigned milliseconds) { + state.milliseconds = milliseconds; + return p.setInterval(milliseconds); +} + +Timer::Timer(): +state(*new State), +base_from_member(*new pTimer(*this)), +Object(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Timer::~Timer() { + p.destructor(); + delete &state; +} + +//MessageWindow +//============= + +MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::information(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::question(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::warning(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::critical(parent, text, buttons); +} + +//Window +//====== + +void Window::append(Layout &layout) { + if(state.layout.append(layout)) { + ((Sizable&)layout).state.window = this; + ((Sizable&)layout).state.layout = 0; + p.append(layout); + layout.synchronizeLayout(); + } +} + +void Window::append(Menu &menu) { + if(state.menu.append(menu)) { + ((Action&)menu).state.window = this; + p.append(menu); + } +} + +void Window::append(Widget &widget) { + if(state.widget.append(widget)) { + ((Sizable&)widget).state.window = this; + p.append(widget); + } +} + +Color Window::backgroundColor() { + return p.backgroundColor(); +} + +Geometry Window::frameGeometry() { + Geometry geometry = p.geometry(); + Geometry margin = p.frameMargin(); + return { + geometry.x - margin.x, geometry.y - margin.y, + geometry.width + margin.width, geometry.height + margin.height + }; +} + +Geometry Window::frameMargin() { + return p.frameMargin(); +} + +bool Window::focused() { + return p.focused(); +} + +bool Window::fullScreen() { + return state.fullScreen; +} + +Geometry Window::geometry() { + return p.geometry(); +} + +void Window::ignore() { + state.ignore = true; +} + +void Window::remove(Layout &layout) { + if(state.layout.remove(layout)) { + p.remove(layout); + ((Sizable&)layout).state.window = 0; + } +} + +void Window::remove(Menu &menu) { + if(state.menu.remove(menu)) { + p.remove(menu); + ((Action&)menu).state.window = 0; + } +} + +void Window::remove(Widget &widget) { + if(state.widget.remove(widget)) { + p.remove(widget); + ((Sizable&)widget).state.window = 0; + } +} + +void Window::setBackgroundColor(const Color &color) { + state.backgroundColorOverride = true; + state.backgroundColor = color; + return p.setBackgroundColor(color); +} + +void Window::setFrameGeometry(const Geometry &geometry) { + Geometry margin = p.frameMargin(); + return setGeometry({ + geometry.x + margin.x, geometry.y + margin.y, + geometry.width - margin.width, geometry.height - margin.height + }); +} + +void Window::setFocused() { + return p.setFocused(); +} + +void Window::setFullScreen(bool fullScreen) { + state.fullScreen = fullScreen; + return p.setFullScreen(fullScreen); +} + +void Window::setGeometry(const Geometry &geometry) { + state.geometry = geometry; + return p.setGeometry(geometry); +} + +void Window::setMenuFont(const string &font) { + state.menuFont = font; + return p.setMenuFont(font); +} + +void Window::setMenuVisible(bool visible) { + state.menuVisible = visible; + return p.setMenuVisible(visible); +} + +void Window::setResizable(bool resizable) { + state.resizable = resizable; + return p.setResizable(resizable); +} + +void Window::setStatusFont(const string &font) { + state.statusFont = font; + return p.setStatusFont(font); +} + +void Window::setStatusText(const string &text) { + state.statusText = text; + return p.setStatusText(text); +} + +void Window::setStatusVisible(bool visible) { + state.statusVisible = visible; + return p.setStatusVisible(visible); +} + +void Window::setTitle(const string &text) { + state.title = text; + return p.setTitle(text); +} + +void Window::setVisible(bool visible) { + state.visible = visible; + synchronizeLayout(); + return p.setVisible(visible); +} + +void Window::setWidgetFont(const string &font) { + state.widgetFont = font; + return p.setWidgetFont(font); +} + +string Window::statusText() { + return state.statusText; +} + +void Window::synchronizeLayout() { + if(visible() && OS_quit == false) setGeometry(geometry()); +} + +bool Window::visible() { + return state.visible; +} + +Window::Window(): +state(*new State), +base_from_member(*new pWindow(*this)), +Object(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Window::~Window() { + p.destructor(); + delete &state; +} + +//Action +//====== + +bool Action::enabled() { + return state.enabled; +} + +void Action::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} + +void Action::setVisible(bool visible) { + state.visible = visible; + return p.setVisible(visible); +} + +bool Action::visible() { + return state.visible; +} + +Action::Action(pAction &p): +state(*new State), +Object(p), +p(p) { + p.constructor(); +} + +Action::~Action() { + p.destructor(); + delete &state; +} + +//Menu +//==== + +void Menu::append(Action &action) { + if(state.action.append(action)) { + action.state.menu = this; + return p.append(action); + } +} + +void Menu::remove(Action &action) { + if(state.action.remove(action)) { + action.state.menu = 0; + return p.remove(action); + } +} + +void Menu::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Menu::Menu(): +state(*new State), +base_from_member(*new pMenu(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Menu::~Menu() { + p.destructor(); + delete &state; +} + +//Separator +//========= + +Separator::Separator(): +base_from_member(*new pSeparator(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Separator::~Separator() { + p.destructor(); +} + +//Item +//==== + +void Item::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Item::Item(): +state(*new State), +base_from_member(*new pItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Item::~Item() { + p.destructor(); + delete &state; +} + +//CheckItem +//========= + +bool CheckItem::checked() { + return p.checked(); +} + +void CheckItem::setChecked(bool checked) { + state.checked = checked; + return p.setChecked(checked); +} + +void CheckItem::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +CheckItem::CheckItem(): +state(*new State), +base_from_member(*new pCheckItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +CheckItem::~CheckItem() { + p.destructor(); + delete &state; +} + +//RadioItem +//========= + +void RadioItem::group(const reference_array &list) { + for(auto &item : list) item.p.setGroup(item.state.group = list); + if(list.size()) list[0].setChecked(); +} + +bool RadioItem::checked() { + return p.checked(); +} + +void RadioItem::setChecked() { + for(auto &item : state.group) item.state.checked = false; + state.checked = true; + return p.setChecked(); +} + +void RadioItem::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +RadioItem::RadioItem(): +state(*new State), +base_from_member(*new pRadioItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +RadioItem::~RadioItem() { + for(auto &item : state.group) { + if(&item != this) item.state.group.remove(*this); + } + p.destructor(); + delete &state; +} + +//Sizable +//======= + +Layout* Sizable::layout() { + return state.layout; +} + +Window* Sizable::window() { + if(state.layout) return state.layout->window(); + return state.window; +} + +Sizable::Sizable(pSizable &p): +state(*new State), +Object(p), +p(p) { + p.constructor(); +} + +Sizable::~Sizable() { + if(layout()) layout()->remove(*this); + p.destructor(); + delete &state; +} + +//Layout +//====== + +void Layout::append(Sizable &sizable) { + sizable.state.layout = this; + sizable.state.window = 0; + + if(dynamic_cast(&sizable)) { + Layout &layout = (Layout&)sizable; + layout.synchronizeLayout(); + } + + if(dynamic_cast(&sizable)) { + Widget &widget = (Widget&)sizable; + if(sizable.window()) sizable.window()->append(widget); + } +} + +void Layout::remove(Sizable &sizable) { + if(dynamic_cast(&sizable)) { + Widget &widget = (Widget&)sizable; + if(sizable.window()) sizable.window()->remove(widget); + } + + sizable.state.layout = 0; + sizable.state.window = 0; +} + +Layout::Layout(): +state(*new State), +base_from_member(*new pLayout(*this)), +Sizable(base_from_member::value), +p(base_from_member::value) { +} + +Layout::Layout(pLayout &p): +state(*new State), +base_from_member(p), +Sizable(p), +p(p) { +} + +Layout::~Layout() { + if(layout()) layout()->remove(*this); + else if(window()) window()->remove(*this); + p.destructor(); + delete &state; +} + +//Widget +//====== + +bool Widget::enabled() { + return state.enabled; +} + +string Widget::font() { + return state.font; +} + +Geometry Widget::geometry() { + return state.geometry; +} + +Geometry Widget::minimumGeometry() { + return p.minimumGeometry(); +} + +void Widget::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} + +void Widget::setFocused() { + return p.setFocused(); +} + +void Widget::setFont(const string &font) { + state.font = font; + return p.setFont(font); +} + +void Widget::setGeometry(const Geometry &geometry) { + state.geometry = geometry; + return p.setGeometry(geometry); +} + +void Widget::setVisible(bool visible) { + state.visible = visible; + return p.setVisible(visible); +} + +bool Widget::visible() { + return state.visible; +} + +Widget::Widget(): +state(*new State), +base_from_member(*new pWidget(*this)), +Sizable(base_from_member::value), +p(base_from_member::value) { + state.abstract = true; + p.constructor(); +} + +Widget::Widget(pWidget &p): +state(*new State), +base_from_member(p), +Sizable(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Widget::~Widget() { + p.destructor(); + delete &state; +} + +//Button +//====== + +void Button::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Button::Button(): +state(*new State), +base_from_member(*new pButton(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Button::~Button() { + p.destructor(); + delete &state; +} + +//Canvas +//====== + +uint32_t* Canvas::data() { + return state.data; +} + +bool Canvas::setImage(const Image &image) { + if(image.data == nullptr || image.width == 0 || image.height == 0) return false; + state.width = image.width; + state.height = image.height; + setSize({ state.width, state.height }); + memcpy(state.data, image.data, state.width * state.height * sizeof(uint32_t)); + return true; +} + +void Canvas::setSize(const Size &size) { + state.width = size.width; + state.height = size.height; + delete[] state.data; + state.data = new uint32_t[size.width * size.height]; + return p.setSize(size); +} + +Size Canvas::size() { + return { state.width, state.height }; +} + +void Canvas::update() { + return p.update(); +} + +Canvas::Canvas(): +state(*new State), +base_from_member(*new pCanvas(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + state.data = new uint32_t[state.width * state.height]; + p.constructor(); +} + +Canvas::~Canvas() { + p.destructor(); + delete[] state.data; + delete &state; +} + +//CheckBox +//======== + +bool CheckBox::checked() { + return p.checked(); +} + +void CheckBox::setChecked(bool checked) { + state.checked = checked; + return p.setChecked(checked); +} + +void CheckBox::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +CheckBox::CheckBox(): +state(*new State), +base_from_member(*new pCheckBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +CheckBox::~CheckBox() { + p.destructor(); + delete &state; +} + +//ComboBox +//======== + +void ComboBox::append(const string &text) { + state.text.append(text); + return p.append(text); +} + +void ComboBox::reset() { + state.selection = 0; + state.text.reset(); + return p.reset(); +} + +unsigned ComboBox::selection() { + return p.selection(); +} + +void ComboBox::setSelection(unsigned row) { + state.selection = row; + return p.setSelection(row); +} + +ComboBox::ComboBox(): +state(*new State), +base_from_member(*new pComboBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ComboBox::~ComboBox() { + p.destructor(); + delete &state; +} + +//HexEdit +//======= + +void HexEdit::setColumns(unsigned columns) { + state.columns = columns; + return p.setColumns(columns); +} + +void HexEdit::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HexEdit::setOffset(unsigned offset) { + state.offset = offset; + return p.setOffset(offset); +} + +void HexEdit::setRows(unsigned rows) { + state.rows = rows; + return p.setRows(rows); +} + +void HexEdit::update() { + return p.update(); +} + +HexEdit::HexEdit(): +state(*new State), +base_from_member(*new pHexEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HexEdit::~HexEdit() { + p.destructor(); + delete &state; +} + +//HorizontalScrollBar +//=================== + +unsigned HorizontalScrollBar::length() { + return state.length; +} + +unsigned HorizontalScrollBar::position() { + return p.position(); +} + +void HorizontalScrollBar::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HorizontalScrollBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +HorizontalScrollBar::HorizontalScrollBar(): +state(*new State), +base_from_member(*new pHorizontalScrollBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HorizontalScrollBar::~HorizontalScrollBar() { + p.destructor(); + delete &state; +} + +//HorizontalSlider +//================ + +unsigned HorizontalSlider::length() { + return state.length; +} + +unsigned HorizontalSlider::position() { + return p.position(); +} + +void HorizontalSlider::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HorizontalSlider::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +HorizontalSlider::HorizontalSlider(): +state(*new State), +base_from_member(*new pHorizontalSlider(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HorizontalSlider::~HorizontalSlider() { + p.destructor(); + delete &state; +} + +//Label +//===== + +void Label::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Label::Label(): +state(*new State), +base_from_member(*new pLabel(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Label::~Label() { + p.destructor(); + delete &state; +} + +//LineEdit +//======== + +void LineEdit::setEditable(bool editable) { + state.editable = editable; + return p.setEditable(editable); +} + +void LineEdit::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +string LineEdit::text() { + return p.text(); +} + +LineEdit::LineEdit(): +state(*new State), +base_from_member(*new pLineEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +LineEdit::~LineEdit() { + p.destructor(); + delete &state; +} + +//ListView +//======== + +void ListView::append_(const lstring &text) { + state.checked.append(false); + state.text.append(text); + return p.append(text); +} + +void ListView::autoSizeColumns() { + return p.autoSizeColumns(); +} + +bool ListView::checked(unsigned row) { + return p.checked(row); +} + +void ListView::modify_(unsigned row, const lstring &text) { + state.text[row] = text; + return p.modify(row, text); +} + +void ListView::reset() { + state.checked.reset(); + state.text.reset(); + return p.reset(); +} + +bool ListView::selected() { + return p.selected(); +} + +unsigned ListView::selection() { + return p.selection(); +} + +void ListView::setCheckable(bool checkable) { + state.checkable = checkable; + return p.setCheckable(checkable); +} + +void ListView::setChecked(unsigned row, bool checked) { + state.checked[row] = checked; + return p.setChecked(row, checked); +} + +void ListView::setHeaderText_(const lstring &text) { + state.headerText = text; + return p.setHeaderText(text); +} + +void ListView::setHeaderVisible(bool visible) { + state.headerVisible = visible; + return p.setHeaderVisible(visible); +} + +void ListView::setSelected(bool selected) { + state.selected = selected; + return p.setSelected(selected); +} + +void ListView::setSelection(unsigned row) { + state.selected = true; + state.selection = row; + return p.setSelection(row); +} + +ListView::ListView(): +state(*new State), +base_from_member(*new pListView(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ListView::~ListView() { + p.destructor(); + delete &state; +} + +//ProgressBar +//=========== + +void ProgressBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +ProgressBar::ProgressBar(): +state(*new State), +base_from_member(*new pProgressBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ProgressBar::~ProgressBar() { + p.destructor(); + delete &state; +} + +//RadioBox +//======== + +void RadioBox::group(const reference_array &list) { + for(auto &item : list) item.p.setGroup(item.state.group = list); + if(list.size()) list[0].setChecked(); +} + +bool RadioBox::checked() { + return p.checked(); +} + +void RadioBox::setChecked() { + for(auto &item : state.group) item.state.checked = false; + state.checked = true; + return p.setChecked(); +} + +void RadioBox::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +RadioBox::RadioBox(): +state(*new State), +base_from_member(*new pRadioBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +RadioBox::~RadioBox() { + for(auto &item : state.group) { + if(&item != this) item.state.group.remove(*this); + } + p.destructor(); + delete &state; +} + +//TextEdit +//======== + +void TextEdit::setCursorPosition(unsigned position) { + state.cursorPosition = position; + return p.setCursorPosition(position); +} + +void TextEdit::setEditable(bool editable) { + state.editable = editable; + return p.setEditable(editable); +} + +void TextEdit::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +void TextEdit::setWordWrap(bool wordWrap) { + state.wordWrap = wordWrap; + return p.setWordWrap(wordWrap); +} + +string TextEdit::text() { + return p.text(); +} + +TextEdit::TextEdit(): +state(*new State), +base_from_member(*new pTextEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +TextEdit::~TextEdit() { + p.destructor(); + delete &state; +} + +//VerticalScrollBar +//================= + +unsigned VerticalScrollBar::length() { + return state.length; +} + +unsigned VerticalScrollBar::position() { + return p.position(); +} + +void VerticalScrollBar::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void VerticalScrollBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +VerticalScrollBar::VerticalScrollBar(): +state(*new State), +base_from_member(*new pVerticalScrollBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +VerticalScrollBar::~VerticalScrollBar() { + p.destructor(); + delete &state; +} + +//VerticalSlider +//============== + +unsigned VerticalSlider::length() { + return state.length; +} + +unsigned VerticalSlider::position() { + return p.position(); +} + +void VerticalSlider::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void VerticalSlider::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +VerticalSlider::VerticalSlider(): +state(*new State), +base_from_member(*new pVerticalSlider(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +VerticalSlider::~VerticalSlider() { + p.destructor(); + delete &state; +} + +//Viewport +//======== + +uintptr_t Viewport::handle() { + return p.handle(); +} + +Viewport::Viewport(): +base_from_member(*new pViewport(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Viewport::~Viewport() { + p.destructor(); +} diff --git a/phoenix/core/core.hpp b/phoenix/core/core.hpp new file mode 100755 index 00000000..d75b1efc --- /dev/null +++ b/phoenix/core/core.hpp @@ -0,0 +1,560 @@ +struct Font; +struct Window; +struct Menu; +struct Sizable; +struct Layout; +struct Widget; + +struct pFont; +struct pObject; +struct pOS; +struct pTimer; +struct pWindow; +struct pAction; +struct pMenu; +struct pSeparator; +struct pItem; +struct pCheckItem; +struct pRadioItem; +struct pSizable; +struct pLayout; +struct pWidget; +struct pButton; +struct pCanvas; +struct pCheckBox; +struct pComboBox; +struct pHexEdit; +struct pHorizontalScrollBar; +struct pHorizontalSlider; +struct pLabel; +struct pLineEdit; +struct pListView; +struct pProgressBar; +struct pRadioBox; +struct pTextEdit; +struct pVerticalScrollBar; +struct pVerticalSlider; +struct pViewport; + +enum : unsigned { + MaximumSize = ~0u, + MinimumSize = 0u, +}; + +struct Color { + uint8_t red, green, blue, alpha; + inline Color() : red(0), green(0), blue(0), alpha(255) {} + inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {} +}; + +struct Geometry { + signed x, y; + unsigned width, height; + inline Geometry() : x(0), y(0), width(0), height(0) {} + inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {} +}; + +struct Position { + signed x, y; + inline Position() : x(0), y(0) {} + inline Position(signed x, signed y) : x(x), y(y) {} +}; + +struct Size { + unsigned width, height; + inline Size() : width(0), height(0) {} + inline Size(unsigned width, unsigned height) : width(width), height(height) {} +}; + +struct Font { + nall::string description; + Geometry geometry(const nall::string &text); + Font(const nall::string &description = ""); +}; + +struct Image { + uint32_t *data; + unsigned width, height; + bool load(const nall::string &filename, const Color &alpha = Color{255, 255, 255}); + void load(const uint32_t *data, const Size &size); + Image& operator=(const Image &source); + Image& operator=(Image &&source); + Image(); + Image(const nall::string &filename, const Color &alpha = Color{255, 255, 255}); + Image(const uint32_t *data, const Size &size); + Image(const Image &source); + Image(Image &&source); + ~Image(); +}; + +struct Object { + Object(pObject &p); + Object& operator=(const Object&) = delete; + Object(const Object&) = delete; + virtual ~Object(); + pObject &p; +}; + +struct OS : Object { + static Geometry availableGeometry(); + static Geometry desktopGeometry(); + template static nall::string fileLoad(Window &parent, const nall::string &path, const Args&... args) { return fileLoad_(parent, path, { args... }); } + template static nall::string fileSave(Window &parent, const nall::string &path, const Args&... args) { return fileSave_(parent, path, { args... }); } + static nall::string folderSelect(Window &parent, const nall::string &path); + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + OS(); + static void initialize(); + +private: + static nall::string fileLoad_(Window &parent, const nall::string &path, const nall::lstring& filter); + static nall::string fileSave_(Window &parent, const nall::string &path, const nall::lstring& filter); +}; + +struct Timer : private nall::base_from_member, Object { + nall::function onTimeout; + + void setEnabled(bool enabled = true); + void setInterval(unsigned milliseconds); + + Timer(); + ~Timer(); + struct State; + State &state; + pTimer &p; +}; + +struct MessageWindow : Object { + enum class Buttons : unsigned { + Ok, + OkCancel, + YesNo, + }; + + enum class Response : unsigned { + Ok, + Cancel, + Yes, + No, + }; + + static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok); + static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo); + static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok); + static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok); +}; + +struct Window : private nall::base_from_member, Object { + static Window None; + nall::function onClose; + nall::function onMove; + nall::function onSize; + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + Geometry frameGeometry(); + Geometry frameMargin(); + bool focused(); + bool fullScreen(); + Geometry geometry(); + void ignore(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFrameGeometry(const Geometry &geometry); + void setFocused(); + void setFullScreen(bool fullScreen = true); + void setGeometry(const Geometry &geometry); + void setMenuFont(const nall::string &font); + void setMenuVisible(bool visible = true); + void setResizable(bool resizable = true); + void setStatusFont(const nall::string &font); + void setStatusText(const nall::string &text); + void setStatusVisible(bool visible = true); + void setTitle(const nall::string &text); + void setVisible(bool visible = true); + void setWidgetFont(const nall::string &font); + nall::string statusText(); + void synchronizeLayout(); + bool visible(); + + Window(); + ~Window(); + struct State; + State &state; + pWindow &p; +}; + +struct Action : Object { + bool enabled(); + void setEnabled(bool enabled = true); + void setVisible(bool visible = true); + bool visible(); + + Action(pAction &p); + ~Action(); + struct State; + State &state; + pAction &p; +}; + +struct Menu : private nall::base_from_member, Action { + void append(Action &action); + void remove(Action &action); + void setText(const nall::string &text); + + Menu(); + ~Menu(); + struct State; + State &state; + pMenu &p; +}; + +struct Separator : private nall::base_from_member, Action { + Separator(); + ~Separator(); + pSeparator &p; +}; + +struct Item : private nall::base_from_member, Action { + nall::function onTick; + + void setText(const nall::string &text); + + Item(); + ~Item(); + struct State; + State &state; + pItem &p; +}; + +struct CheckItem : private nall::base_from_member, Action { + nall::function onTick; + + bool checked(); + void setChecked(bool checked = true); + void setText(const nall::string &text); + + CheckItem(); + ~CheckItem(); + struct State; + State &state; + pCheckItem &p; +}; + +struct RadioItem : private nall::base_from_member, Action { + template static void group(Args&... args) { group({ args... }); } + static void group(const nall::reference_array &list); + + nall::function onTick; + + bool checked(); + void setChecked(); + void setText(const nall::string &text); + + RadioItem(); + ~RadioItem(); + struct State; + State &state; + pRadioItem &p; +}; + +struct Sizable : Object { + virtual bool enabled() = 0; + Layout* layout(); + virtual Geometry minimumGeometry() = 0; + virtual void setEnabled(bool enabled = true) = 0; + virtual void setGeometry(const Geometry &geometry) = 0; + virtual void setVisible(bool visible = true) = 0; + virtual bool visible() = 0; + Window* window(); + + Sizable(pSizable &p); + ~Sizable(); + struct State; + State &state; + pSizable &p; +}; + +struct Layout : private nall::base_from_member, Sizable { + virtual void append(Sizable &sizable); + virtual void remove(Sizable &sizable); + virtual void reset() {} + virtual void synchronizeLayout() = 0; + + Layout(); + Layout(pLayout &p); + ~Layout(); + struct State; + State &state; + pLayout &p; +}; + +struct Widget : private nall::base_from_member, Sizable { + bool enabled(); + nall::string font(); + Geometry geometry(); + Geometry minimumGeometry(); + void setEnabled(bool enabled = true); + void setFocused(); + void setFont(const nall::string &font); + void setGeometry(const Geometry &geometry); + void setVisible(bool visible = true); + bool visible(); + + Widget(); + Widget(pWidget &p); + ~Widget(); + struct State; + State &state; + pWidget &p; +}; + +struct Button : private nall::base_from_member, Widget { + nall::function onTick; + + void setText(const nall::string &text); + + Button(); + ~Button(); + struct State; + State &state; + pButton &p; +}; + +struct Canvas : private nall::base_from_member, Widget { + uint32_t* data(); + bool setImage(const Image &image); + void setSize(const Size &size); + Size size(); + void update(); + + Canvas(); + ~Canvas(); + struct State; + State &state; + pCanvas &p; +}; + +struct CheckBox : private nall::base_from_member, Widget { + nall::function onTick; + + bool checked(); + void setChecked(bool checked = true); + void setText(const nall::string &text); + + CheckBox(); + ~CheckBox(); + struct State; + State &state; + pCheckBox &p; +}; + +struct ComboBox : private nall::base_from_member, Widget { + nall::function onChange; + + void append(const nall::string &text); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + ComboBox(); + ~ComboBox(); + struct State; + State &state; + pComboBox &p; +}; + +struct HexEdit : private nall::base_from_member, Widget { + nall::function onRead; + nall::function onWrite; + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + HexEdit(); + ~HexEdit(); + struct State; + State &state; + pHexEdit &p; +}; + +struct HorizontalScrollBar : private nall::base_from_member, Widget { + nall::function onChange; + + unsigned length(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + HorizontalScrollBar(); + ~HorizontalScrollBar(); + struct State; + State &state; + pHorizontalScrollBar &p; +}; + +struct HorizontalSlider : private nall::base_from_member, Widget { + nall::function onChange; + + unsigned length(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + HorizontalSlider(); + ~HorizontalSlider(); + struct State; + State &state; + pHorizontalSlider &p; +}; + +struct Label : private nall::base_from_member, Widget { + void setText(const nall::string &text); + + Label(); + ~Label(); + struct State; + State &state; + pLabel &p; +}; + +struct LineEdit : private nall::base_from_member, Widget { + nall::function onActivate; + nall::function onChange; + + void setEditable(bool editable = true); + void setText(const nall::string &text); + nall::string text(); + + LineEdit(); + ~LineEdit(); + struct State; + State &state; + pLineEdit &p; +}; + +struct ListView : private nall::base_from_member, Widget { + nall::function onActivate; + nall::function onChange; + nall::function onTick; + + template void append(const Args&... args) { append_({ args... }); } + void autoSizeColumns(); + bool checked(unsigned row); + template void modify(unsigned row, const Args&... args) { modify_(row, { args... }); } + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable = true); + void setChecked(unsigned row, bool checked = true); + template void setHeaderText(const Args&... args) { setHeaderText_({ args... }); } + void setHeaderVisible(bool visible = true); + void setSelected(bool selected = true); + void setSelection(unsigned row); + + ListView(); + ~ListView(); + struct State; + State &state; + pListView &p; + +private: + void append_(const nall::lstring &list); + void modify_(unsigned row, const nall::lstring &list); + void setHeaderText_(const nall::lstring &list); +}; + +struct ProgressBar : private nall::base_from_member, Widget { + void setPosition(unsigned position); + + ProgressBar(); + ~ProgressBar(); + struct State; + State &state; + pProgressBar &p; +}; + +struct RadioBox : private nall::base_from_member, Widget { + template static void group(Args&... args) { group({ args... }); } + static void group(const nall::reference_array &list); + + nall::function onTick; + + bool checked(); + void setChecked(); + void setText(const nall::string &text); + + RadioBox(); + ~RadioBox(); + struct State; + State &state; + pRadioBox &p; +}; + +struct TextEdit : private nall::base_from_member, Widget { + nall::function onChange; + + void setCursorPosition(unsigned position); + void setEditable(bool editable = true); + void setText(const nall::string &text); + void setWordWrap(bool wordWrap = true); + nall::string text(); + + TextEdit(); + ~TextEdit(); + struct State; + State &state; + pTextEdit &p; +}; + +struct VerticalScrollBar : private nall::base_from_member, Widget { + nall::function onChange; + + unsigned length(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + VerticalScrollBar(); + ~VerticalScrollBar(); + struct State; + State &state; + pVerticalScrollBar &p; +}; + +struct VerticalSlider : private nall::base_from_member, Widget { + nall::function onChange; + + unsigned length(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + VerticalSlider(); + ~VerticalSlider(); + struct State; + State &state; + pVerticalSlider &p; +}; + +struct Viewport : private nall::base_from_member, Widget { + uintptr_t handle(); + + Viewport(); + ~Viewport(); + pViewport &p; +}; + +#include "layout/fixed-layout.hpp" +#include "layout/horizontal-layout.hpp" +#include "layout/vertical-layout.hpp" diff --git a/phoenix/core/layout/fixed-layout.cpp b/phoenix/core/layout/fixed-layout.cpp new file mode 100755 index 00000000..71ff3dac --- /dev/null +++ b/phoenix/core/layout/fixed-layout.cpp @@ -0,0 +1,80 @@ +void FixedLayout::append(Sizable &sizable, const Geometry &geometry) { + children.append({ &sizable, geometry }); + synchronizeLayout(); + if(window()) window()->synchronizeLayout(); +} + +void FixedLayout::append(Sizable &sizable) { + for(auto &child : children) if(child.sizable == &sizable) return; + Layout::append(sizable); + if(window()) window()->synchronizeLayout(); +} + +bool FixedLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; +} + +Geometry FixedLayout::minimumGeometry() { + unsigned width = MinimumSize, height = MinimumSize; + for(auto &child : children) { + width = max(width, child.sizable->minimumGeometry().width); + height = max(height, child.sizable->minimumGeometry().height); + } + return { 0, 0, width, height }; +} + +void FixedLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + children.remove(n); + Layout::remove(sizable); + if(window()) window()->synchronizeLayout(); + break; + } + } +} + +void FixedLayout::reset() { + for(auto &child : children) { + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); + } +} + +void FixedLayout::setEnabled(bool enabled) { + state.enabled = enabled; + for(auto &child : children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } +} + +void FixedLayout::setGeometry(const Geometry &geometry) { +} + +void FixedLayout::setVisible(bool visible) { + state.visible = visible; + for(auto &child : children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); + } +} + +void FixedLayout::synchronizeLayout() { + for(auto &child : children) { + Layout::append(*child.sizable); + child.sizable->setGeometry(child.geometry); + } +} + +bool FixedLayout::visible() { + if(layout()) return state.visible && layout()->visible(); + return state.visible; +} + +FixedLayout::FixedLayout() { + state.enabled = true; + state.visible = true; +} + +FixedLayout::~FixedLayout() { + while(children.size()) remove(*children[0].sizable); +} diff --git a/phoenix/core/layout/fixed-layout.hpp b/phoenix/core/layout/fixed-layout.hpp new file mode 100755 index 00000000..a67f2185 --- /dev/null +++ b/phoenix/core/layout/fixed-layout.hpp @@ -0,0 +1,27 @@ +struct FixedLayout : Layout { + void append(Sizable &sizable, const Geometry &geometry); + void append(Sizable &sizable); + bool enabled(); + Geometry minimumGeometry(); + void remove(Sizable &sizable); + void reset(); + void setEnabled(bool enabled = true); + void setGeometry(const Geometry &geometry); + void setVisible(bool visible = true); + void synchronizeLayout(); + bool visible(); + FixedLayout(); + ~FixedLayout(); + +//private: + struct State { + bool enabled; + bool visible; + } state; + + struct Children { + Sizable *sizable; + Geometry geometry; + }; + nall::vector children; +}; diff --git a/phoenix/core/layout/horizontal-layout.cpp b/phoenix/core/layout/horizontal-layout.cpp new file mode 100755 index 00000000..a1146038 --- /dev/null +++ b/phoenix/core/layout/horizontal-layout.cpp @@ -0,0 +1,142 @@ +void HorizontalLayout::append(Sizable &sizable, const Size &size, unsigned spacing) { + for(auto &child : children) if(child.sizable == &sizable) return; + children.append({ &sizable, size.width, size.height, spacing }); + synchronizeLayout(); + if(window()) window()->synchronizeLayout(); +} + +void HorizontalLayout::append(Sizable &sizable) { + for(auto &child : children) if(child.sizable == &sizable) return; + Layout::append(sizable); + if(window()) window()->synchronizeLayout(); +} + +bool HorizontalLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; +} + +Geometry HorizontalLayout::minimumGeometry() { + unsigned width = 0, height = 0; + + for(auto &child : children) { + width += child.spacing; + if(child.width == MinimumSize || child.width == MaximumSize) { + width += child.sizable->minimumGeometry().width; + continue; + } + width += child.width; + } + + for(auto &child : children) { + if(child.height == MinimumSize || child.height == MaximumSize) { + height = max(height, child.sizable->minimumGeometry().height); + continue; + } + height = max(height, child.height); + } + + return { 0, 0, state.margin * 2 + width, state.margin * 2 + height }; +} + +void HorizontalLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + if(dynamic_cast(children[n].sizable)) { + Layout *layout = (Layout*)children[n].sizable; + layout->reset(); + } + children.remove(n); + Layout::remove(sizable); + if(window()) window()->synchronizeLayout(); + break; + } + } +} + +void HorizontalLayout::reset() { + for(auto &child : children) { + if(window() && dynamic_cast(child.sizable)) ((Layout*)child.sizable)->reset(); + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); + } +} + +void HorizontalLayout::setAlignment(double alignment) { + state.alignment = max(0.0, min(1.0, alignment)); +} + +void HorizontalLayout::setEnabled(bool enabled) { + state.enabled = enabled; + for(auto &child : children) { + child.sizable->setEnabled(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } +} + +void HorizontalLayout::setGeometry(const Geometry &containerGeometry) { + auto children = this->children; + for(auto &child : children) { + if(child.width == MinimumSize) child.width = child.sizable->minimumGeometry().width; + if(child.height == MinimumSize) child.height = child.sizable->minimumGeometry().height; + } + + Geometry geometry = containerGeometry; + geometry.x += state.margin; + geometry.y += state.margin; + geometry.width -= state.margin * 2; + geometry.height -= state.margin * 2; + + unsigned minimumWidth = 0, maximumWidthCounter = 0; + for(auto &child : children) { + if(child.width == MaximumSize) maximumWidthCounter++; + if(child.width != MaximumSize) minimumWidth += child.width; + minimumWidth += child.spacing; + } + + for(auto &child : children) { + if(child.width == MaximumSize) child.width = (geometry.width - minimumWidth) / maximumWidthCounter; + if(child.height == MaximumSize) child.height = geometry.height; + } + + unsigned maximumHeight = 0; + for(auto &child : children) maximumHeight = max(maximumHeight, child.height); + + for(auto &child : children) { + unsigned pivot = (maximumHeight - child.height) * state.alignment; + Geometry childGeometry = { geometry.x, geometry.y + pivot, child.width, child.height }; + child.sizable->setGeometry(childGeometry); + + geometry.x += child.width + child.spacing; + geometry.width -= child.width + child.spacing; + } +} + +void HorizontalLayout::setMargin(unsigned margin) { + state.margin = margin; +} + +void HorizontalLayout::setVisible(bool visible) { + state.visible = visible; + for(auto &child : children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); + } +} + +void HorizontalLayout::synchronizeLayout() { + for(auto &child : children) Layout::append(*child.sizable); +} + +bool HorizontalLayout::visible() { + if(layout()) return state.visible && layout()->visible(); + return state.visible; +} + +HorizontalLayout::HorizontalLayout() { + state.alignment = 0.5; + state.enabled = true; + state.margin = 0; + state.visible = true; +} + +HorizontalLayout::~HorizontalLayout() { + while(children.size()) remove(*children[0].sizable); +} diff --git a/phoenix/core/layout/horizontal-layout.hpp b/phoenix/core/layout/horizontal-layout.hpp new file mode 100755 index 00000000..96d4f101 --- /dev/null +++ b/phoenix/core/layout/horizontal-layout.hpp @@ -0,0 +1,31 @@ +struct HorizontalLayout : public Layout { + void append(Sizable &sizable, const Size &size, unsigned spacing = 0); + void append(Sizable &sizable); + bool enabled(); + Geometry minimumGeometry(); + void remove(Sizable &sizable); + void reset(); + void setAlignment(double alignment); + void setEnabled(bool enabled = true); + void setGeometry(const Geometry &geometry); + void setMargin(unsigned margin); + void setVisible(bool visible = true); + void synchronizeLayout(); + bool visible(); + HorizontalLayout(); + ~HorizontalLayout(); + +//private: + struct State { + double alignment; + bool enabled; + unsigned margin; + bool visible; + } state; + + struct Children { + Sizable *sizable; + unsigned width, height, spacing; + }; + nall::vector children; +}; diff --git a/phoenix/core/layout/vertical-layout.cpp b/phoenix/core/layout/vertical-layout.cpp new file mode 100755 index 00000000..4fd6315b --- /dev/null +++ b/phoenix/core/layout/vertical-layout.cpp @@ -0,0 +1,142 @@ +void VerticalLayout::append(Sizable &sizable, const Size &size, unsigned spacing) { + for(auto &child : children) if(child.sizable == &sizable) return; + children.append({ &sizable, size.width, size.height, spacing }); + synchronizeLayout(); + if(window()) window()->synchronizeLayout(); +} + +void VerticalLayout::append(Sizable &sizable) { + for(auto &child : children) if(child.sizable == &sizable) return; + Layout::append(sizable); + if(window()) window()->synchronizeLayout(); +} + +bool VerticalLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; +} + +Geometry VerticalLayout::minimumGeometry() { + unsigned width = 0, height = 0; + + for(auto &child : children) { + if(child.width == MinimumSize || child.width == MaximumSize) { + width = max(width, child.sizable->minimumGeometry().width); + continue; + } + width = max(width, child.width); + } + + for(auto &child : children) { + height += child.spacing; + if(child.height == MinimumSize || child.height == MaximumSize) { + height += child.sizable->minimumGeometry().height; + continue; + } + height += child.height; + } + + return { 0, 0, state.margin * 2 + width, state.margin * 2 + height }; +} + +void VerticalLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + if(dynamic_cast(children[n].sizable)) { + Layout *layout = (Layout*)children[n].sizable; + layout->reset(); + } + children.remove(n); + Layout::remove(sizable); + if(window()) window()->synchronizeLayout(); + break; + } + } +} + +void VerticalLayout::reset() { + for(auto &child : children) { + if(window() && dynamic_cast(child.sizable)) ((Layout*)child.sizable)->reset(); + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); + } +} + +void VerticalLayout::setAlignment(double alignment) { + state.alignment = max(0.0, min(1.0, alignment)); +} + +void VerticalLayout::setEnabled(bool enabled) { + state.enabled = enabled; + for(auto &child : children) { + child.sizable->setEnabled(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } +} + +void VerticalLayout::setGeometry(const Geometry &containerGeometry) { + auto children = this->children; + for(auto &child : children) { + if(child.width == MinimumSize) child.width = child.sizable->minimumGeometry().width; + if(child.height == MinimumSize) child.height = child.sizable->minimumGeometry().height; + } + + Geometry geometry = containerGeometry; + geometry.x += state.margin; + geometry.y += state.margin; + geometry.width -= state.margin * 2; + geometry.height -= state.margin * 2; + + unsigned minimumHeight = 0, maximumHeightCounter = 0; + for(auto &child : children) { + if(child.height == MaximumSize) maximumHeightCounter++; + if(child.height != MaximumSize) minimumHeight += child.height; + minimumHeight += child.spacing; + } + + for(auto &child : children) { + if(child.width == MaximumSize) child.width = geometry.width; + if(child.height == MaximumSize) child.height = (geometry.height - minimumHeight) / maximumHeightCounter; + } + + unsigned maximumWidth = 0; + for(auto &child : children) maximumWidth = max(maximumWidth, child.width); + + for(auto &child : children) { + unsigned pivot = (maximumWidth - child.width) * state.alignment; + Geometry childGeometry = { geometry.x + pivot, geometry.y, child.width, child.height }; + child.sizable->setGeometry(childGeometry); + + geometry.y += child.height + child.spacing; + geometry.height -= child.height + child.spacing; + } +} + +void VerticalLayout::setMargin(unsigned margin) { + state.margin = margin; +} + +void VerticalLayout::setVisible(bool visible) { + state.visible = visible; + for(auto &child : children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); + } +} + +void VerticalLayout::synchronizeLayout() { + for(auto &child : children) Layout::append(*child.sizable); +} + +bool VerticalLayout::visible() { + if(layout()) return state.visible && layout()->visible(); + return state.visible; +} + +VerticalLayout::VerticalLayout() { + state.alignment = 0.0; + state.enabled = true; + state.margin = 0; + state.visible = true; +} + +VerticalLayout::~VerticalLayout() { + while(children.size()) remove(*children[0].sizable); +} diff --git a/phoenix/core/layout/vertical-layout.hpp b/phoenix/core/layout/vertical-layout.hpp new file mode 100755 index 00000000..8273dbe2 --- /dev/null +++ b/phoenix/core/layout/vertical-layout.hpp @@ -0,0 +1,31 @@ +struct VerticalLayout : public Layout { + void append(Sizable &sizable, const Size &size, unsigned spacing = 0); + void append(Sizable &sizable); + bool enabled(); + Geometry minimumGeometry(); + void remove(Sizable &sizable); + void reset(); + void setAlignment(double alignment); + void setEnabled(bool enabled = true); + void setGeometry(const Geometry &geometry); + void setMargin(unsigned margin); + void setVisible(bool visible = true); + void synchronizeLayout(); + bool visible(); + VerticalLayout(); + ~VerticalLayout(); + +//private: + struct State { + double alignment; + bool enabled; + unsigned margin; + bool visible; + } state; + + struct Children { + Sizable *sizable; + unsigned width, height, spacing; + }; + nall::vector children; +}; diff --git a/phoenix/core/state.hpp b/phoenix/core/state.hpp new file mode 100755 index 00000000..136d89e7 --- /dev/null +++ b/phoenix/core/state.hpp @@ -0,0 +1,265 @@ +struct Timer::State { + bool enabled; + unsigned milliseconds; + + State() { + enabled = false; + milliseconds = 0; + } +}; + +struct Window::State { + bool backgroundColorOverride; + Color backgroundColor; + bool fullScreen; + Geometry geometry; + bool ignore; + reference_array layout; + reference_array menu; + string menuFont; + bool menuVisible; + bool resizable; + string statusFont; + string statusText; + bool statusVisible; + string title; + bool visible; + reference_array widget; + string widgetFont; + + State() { + backgroundColorOverride = false; + backgroundColor = { 0, 0, 0, 255 }; + fullScreen = false; + geometry = { 128, 128, 256, 256 }; + ignore = false; + menuVisible = false; + resizable = true; + statusVisible = false; + visible = false; + } +}; + +struct Action::State { + bool enabled; + Menu *menu; + bool visible; + Window *window; + + State() { + enabled = true; + menu = 0; + visible = true; + window = 0; + } +}; + +struct Menu::State { + reference_array action; + string text; +}; + +struct Item::State { + string text; +}; + +struct CheckItem::State { + bool checked; + string text; + + State() { + checked = false; + } +}; + +struct RadioItem::State { + bool checked; + reference_array group; + string text; + + State() { + checked = true; + } +}; + +struct Sizable::State { + Layout *layout; + Window *window; + + State() { + layout = 0; + window = 0; + } +}; + +struct Layout::State { + State() { + } +}; + +struct Widget::State { + bool abstract; + bool enabled; + string font; + Geometry geometry; + bool visible; + + State() { + abstract = false; + enabled = true; + geometry = { 0, 0, 0, 0 }; + visible = true; + } +}; + +struct Button::State { + string text; + + State() { + } +}; + +struct Canvas::State { + uint32_t *data; + unsigned width; + unsigned height; + + State() { + data = nullptr; + width = 256; + height = 256; + } +}; + +struct CheckBox::State { + bool checked; + string text; + + State() { + checked = false; + } +}; + +struct ComboBox::State { + unsigned selection; + vector text; + + State() { + selection = 0; + } +}; + +struct HexEdit::State { + unsigned columns; + unsigned length; + unsigned offset; + unsigned rows; + + State() { + columns = 16; + length = 0; + offset = 0; + rows = 16; + } +}; + +struct HorizontalScrollBar::State { + unsigned length; + unsigned position; + + State() { + length = 101; + position = 0; + } +}; + +struct HorizontalSlider::State { + unsigned length; + unsigned position; + + State() { + length = 101; + position = 0; + } +}; + +struct Label::State { + string text; +}; + +struct LineEdit::State { + bool editable; + string text; + + State() { + editable = true; + } +}; + +struct ListView::State { + bool checkable; + array checked; + lstring headerText; + bool headerVisible; + bool selected; + unsigned selection; + vector text; + + State() { + checkable = false; + headerVisible = false; + selected = false; + selection = 0; + } +}; + +struct ProgressBar::State { + unsigned position; + + State() { + position = 0; + } +}; + +struct RadioBox::State { + bool checked; + reference_array group; + string text; + + State() { + checked = true; + } +}; + +struct TextEdit::State { + unsigned cursorPosition; + bool editable; + string text; + bool wordWrap; + + State() { + cursorPosition = 0; + editable = true; + wordWrap = false; + } +}; + +struct VerticalScrollBar::State { + unsigned length; + unsigned position; + + State() { + length = 101; + position = 0; + } +}; + +struct VerticalSlider::State { + unsigned length; + unsigned position; + + State() { + length = 101; + position = 0; + } +}; diff --git a/phoenix/gtk/action/action.cpp b/phoenix/gtk/action/action.cpp new file mode 100755 index 00000000..6c47e068 --- /dev/null +++ b/phoenix/gtk/action/action.cpp @@ -0,0 +1,17 @@ +void pAction::setEnabled(bool enabled) { + gtk_widget_set_sensitive(widget, enabled); +} + +void pAction::setFont(const string &font) { + pFont::setFont(widget, font); +} + +void pAction::setVisible(bool visible) { + gtk_widget_set_visible(widget, visible); +} + +void pAction::constructor() { +} + +void pAction::orphan() { +} diff --git a/phoenix/gtk/action/check-item.cpp b/phoenix/gtk/action/check-item.cpp new file mode 100755 index 00000000..92beb3cb --- /dev/null +++ b/phoenix/gtk/action/check-item.cpp @@ -0,0 +1,32 @@ +static void CheckItem_tick(CheckItem *self) { + if(self->p.locked == false && self->onTick) self->onTick(); +} + +bool pCheckItem::checked() { + return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); +} + +void pCheckItem::setChecked(bool checked) { + locked = true; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), checked); + locked = false; +} + +void pCheckItem::setText(const string &text) { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text); +} + +void pCheckItem::constructor() { + widget = gtk_check_menu_item_new_with_label(checkItem.state.text); + setChecked(checkItem.state.checked); + g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(CheckItem_tick), (gpointer)&checkItem); +} + +void pCheckItem::destructor() { + gtk_widget_destroy(widget); +} + +void pCheckItem::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/action/item.cpp b/phoenix/gtk/action/item.cpp new file mode 100755 index 00000000..ae442a13 --- /dev/null +++ b/phoenix/gtk/action/item.cpp @@ -0,0 +1,21 @@ +static void Item_tick(Item *self) { + if(self->onTick) self->onTick(); +} + +void pItem::setText(const string &text) { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text); +} + +void pItem::constructor() { + widget = gtk_menu_item_new_with_label(item.state.text); + g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK(Item_tick), (gpointer)&item); +} + +void pItem::destructor() { + gtk_widget_destroy(widget); +} + +void pItem::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/action/menu.cpp b/phoenix/gtk/action/menu.cpp new file mode 100755 index 00000000..9a81dfa3 --- /dev/null +++ b/phoenix/gtk/action/menu.cpp @@ -0,0 +1,41 @@ +void pMenu::append(Action &action) { + action.state.window = this->action.state.window; + + gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), action.p.widget); + if(action.state.window && action.state.window->state.menuFont != "") { + action.p.setFont(action.state.window->state.menuFont); + } + gtk_widget_show(action.p.widget); +} + +void pMenu::remove(Action &action) { + action.p.orphan(); + action.state.window = 0; +} + +void pMenu::setText(const string &text) { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text); +} + +void pMenu::constructor() { + gtkMenu = gtk_menu_new(); + widget = gtk_menu_item_new_with_label(menu.state.text); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), gtkMenu); +} + +void pMenu::destructor() { + gtk_widget_destroy(gtkMenu); + gtk_widget_destroy(widget); +} + +void pMenu::orphan() { + for(auto &action : menu.state.action) action.p.orphan(); + destructor(); + constructor(); + for(auto &action : menu.state.action) append(action); +} + +void pMenu::setFont(const string &font) { + pAction::setFont(font); + for(auto &item : menu.state.action) item.p.setFont(font); +} diff --git a/phoenix/gtk/action/radio-item.cpp b/phoenix/gtk/action/radio-item.cpp new file mode 100755 index 00000000..02a50c98 --- /dev/null +++ b/phoenix/gtk/action/radio-item.cpp @@ -0,0 +1,47 @@ +static void RadioItem_tick(RadioItem *self) { + for(auto &item : self->state.group) item.state.checked = (&item == self); + if(self->p.locked == false && self->checked() && self->onTick) self->onTick(); +} + +bool pRadioItem::checked() { + return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); +} + +void pRadioItem::setChecked() { + locked = true; + for(auto &item : radioItem.state.group) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), false); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), true); + locked = false; +} + +void pRadioItem::setGroup(const reference_array &group) { + for(unsigned n = 0; n < group.size(); n++) { + if(n == 0) continue; + GSList *currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(group[0].p.widget)); + if(currentGroup != gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(group[n].p.widget))) { + gtk_radio_menu_item_set_group(GTK_RADIO_MENU_ITEM(group[n].p.widget), currentGroup); + } + } +} + +void pRadioItem::setText(const string &text) { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text); +} + +void pRadioItem::constructor() { + widget = gtk_radio_menu_item_new_with_label(0, radioItem.state.text); + setGroup(radioItem.state.group); + for(auto &item : radioItem.state.group) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), item.state.checked); + } + g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(RadioItem_tick), (gpointer)&radioItem); +} + +void pRadioItem::destructor() { + gtk_widget_destroy(widget); +} + +void pRadioItem::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/action/separator.cpp b/phoenix/gtk/action/separator.cpp new file mode 100755 index 00000000..8b7a1a6b --- /dev/null +++ b/phoenix/gtk/action/separator.cpp @@ -0,0 +1,12 @@ +void pSeparator::constructor() { + widget = gtk_separator_menu_item_new(); +} + +void pSeparator::destructor() { + gtk_widget_destroy(widget); +} + +void pSeparator::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/font.cpp b/phoenix/gtk/font.cpp new file mode 100755 index 00000000..cb6889d1 --- /dev/null +++ b/phoenix/gtk/font.cpp @@ -0,0 +1,58 @@ +Geometry pFont::geometry(const string &description, const string &text) { + PangoFontDescription *font = create(description); + Geometry geometry = pFont::geometry(font, text); + free(font); + return geometry; +} + +PangoFontDescription* pFont::create(const string &description) { + lstring part; + part.split(",", description); + for(auto &item : part) item.trim(" "); + + string family = "Sans"; + unsigned size = 8u; + bool bold = false; + bool italic = false; + + if(part[0] != "") family = part[0]; + if(part.size() >= 2) size = decimal(part[1]); + if(part.size() >= 3) bold = part[2].position("Bold"); + if(part.size() >= 3) italic = part[2].position("Italic"); + + PangoFontDescription *font = pango_font_description_new(); + pango_font_description_set_family(font, family); + pango_font_description_set_size(font, size * PANGO_SCALE); + pango_font_description_set_weight(font, !bold ? PANGO_WEIGHT_NORMAL : PANGO_WEIGHT_BOLD); + pango_font_description_set_style(font, !italic ? PANGO_STYLE_NORMAL : PANGO_STYLE_OBLIQUE); + return font; +} + +void pFont::free(PangoFontDescription *font) { + pango_font_description_free(font); +} + +Geometry pFont::geometry(PangoFontDescription *font, const string &text) { + PangoContext *context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); + PangoLayout *layout = pango_layout_new(context); + pango_layout_set_font_description(layout, font); + pango_layout_set_text(layout, text, -1); + int width = 0, height = 0; + pango_layout_get_pixel_size(layout, &width, &height); + g_object_unref((gpointer)layout); + return { 0, 0, width, height }; +} + +void pFont::setFont(GtkWidget *widget, const string &font) { + auto gtkFont = pFont::create(font); + pFont::setFont(widget, (gpointer)gtkFont); + pFont::free(gtkFont); +} + +void pFont::setFont(GtkWidget *widget, gpointer font) { + if(font == 0) return; + gtk_widget_modify_font(widget, (PangoFontDescription*)font); + if(GTK_IS_CONTAINER(widget)) { + gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)pFont::setFont, font); + } +} diff --git a/phoenix/gtk/message-window.cpp b/phoenix/gtk/message-window.cpp new file mode 100755 index 00000000..d0b4f7b4 --- /dev/null +++ b/phoenix/gtk/message-window.cpp @@ -0,0 +1,61 @@ +static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, gint response) { + if(response == GTK_RESPONSE_OK) return MessageWindow::Response::Ok; + if(response == GTK_RESPONSE_CANCEL) return MessageWindow::Response::Cancel; + if(response == GTK_RESPONSE_YES) return MessageWindow::Response::Yes; + if(response == GTK_RESPONSE_NO) return MessageWindow::Response::No; + if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + GtkButtonsType buttonsType = GTK_BUTTONS_OK; + if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL; + if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO; + GtkWidget *dialog = gtk_message_dialog_new( + &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, + GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, buttonsType, "%s", (const char*)text + ); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return MessageWindow_response(buttons, response); +} + +MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + GtkButtonsType buttonsType = GTK_BUTTONS_OK; + if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL; + if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO; + GtkWidget *dialog = gtk_message_dialog_new( + &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, + GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, buttonsType, "%s", (const char*)text + ); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return MessageWindow_response(buttons, response); +} + +MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + GtkButtonsType buttonsType = GTK_BUTTONS_OK; + if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL; + if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO; + GtkWidget *dialog = gtk_message_dialog_new( + &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, + GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, buttonsType, "%s", (const char*)text + ); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return MessageWindow_response(buttons, response); +} + +MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + GtkButtonsType buttonsType = GTK_BUTTONS_OK; + if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL; + if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO; + GtkWidget *dialog = gtk_message_dialog_new( + &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, + GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, buttonsType, "%s", (const char*)text + ); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return MessageWindow_response(buttons, response); +} diff --git a/phoenix/gtk/platform.cpp b/phoenix/gtk/platform.cpp new file mode 100755 index 00000000..2b1ee30e --- /dev/null +++ b/phoenix/gtk/platform.cpp @@ -0,0 +1,179 @@ +#include "platform.hpp" + +#include "settings.cpp" +#include "font.cpp" +#include "timer.cpp" +#include "message-window.cpp" +#include "window.cpp" + +#include "action/action.cpp" +#include "action/menu.cpp" +#include "action/separator.cpp" +#include "action/item.cpp" +#include "action/check-item.cpp" +#include "action/radio-item.cpp" + +#include "widget/widget.cpp" +#include "widget/button.cpp" +#include "widget/canvas.cpp" +#include "widget/check-box.cpp" +#include "widget/combo-box.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-box.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +Font pOS::defaultFont; + +Geometry pOS::availableGeometry() { + Display *display = XOpenDisplay(0); + int screen = DefaultScreen(display); + + static Atom atom = X11None; + if(atom == X11None) atom = XInternAtom(display, "_NET_WORKAREA", True); + + int format; + unsigned char *data = 0; + unsigned long items, after; + Atom returnAtom; + + int result = XGetWindowProperty( + display, RootWindow(display, screen), atom, 0, 4, False, XA_CARDINAL, &returnAtom, &format, &items, &after, &data + ); + + XCloseDisplay(display); + + if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) { + unsigned long *workarea = (unsigned long*)data; + return { (signed)workarea[0], (signed)workarea[1], (unsigned)workarea[2], (unsigned)workarea[3] }; + } + + return desktopGeometry(); +} + +Geometry pOS::desktopGeometry() { + return { + 0, 0, + gdk_screen_get_width(gdk_screen_get_default()), + gdk_screen_get_height(gdk_screen_get_default()) + }; +} + +static string pOS_fileDialog(bool save, Window &parent, const string &path, const lstring &filter) { + string name; + + GtkWidget *dialog = gtk_file_chooser_dialog_new( + save == 0 ? "Load File" : "Save File", + &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, + save == 0 ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + (const gchar*)0 + ); + + if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + + for(auto &filterItem : filter) { + GtkFileFilter *gtkFilter = gtk_file_filter_new(); + gtk_file_filter_set_name(gtkFilter, filterItem); + lstring part; + part.split("(", filterItem); + part[1].rtrim<1>(")"); + lstring list; + list.split(",", part[1]); + for(auto &pattern : list) gtk_file_filter_add_pattern(gtkFilter, pattern); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter); + } + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + return name; +} + +string pOS::fileLoad(Window &parent, const string &path, const lstring &filter) { + return pOS_fileDialog(0, parent, path, filter); +} + +string pOS::fileSave(Window &parent, const string &path, const lstring &filter) { + return pOS_fileDialog(1, parent, path, filter); +} + +string pOS::folderSelect(Window &parent, const string &path) { + string name; + + GtkWidget *dialog = gtk_file_chooser_dialog_new( + "Select Folder", + &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + (const gchar*)0 + ); + + if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + if(name == "") return ""; + if(name.endswith("/") == false) name.append("/"); + return name; +} + +void pOS::main() { + gtk_main(); +} + +bool pOS::pendingEvents() { + return gtk_events_pending(); +} + +void pOS::processEvents() { + while(pendingEvents()) gtk_main_iteration_do(false); +} + +void pOS::quit() { + settings->save(); + + gtk_main_quit(); +} + +void pOS::initialize() { + settings = new Settings; + settings->load(); + + int argc = 1; + char *argv[2]; + argv[0] = new char[8]; + argv[1] = 0; + strcpy(argv[0], "phoenix"); + char **argvp = argv; + gtk_init(&argc, &argvp); + + gtk_rc_parse_string( + "style \"phoenix-gtk\"\n" + "{\n" + " GtkComboBox::appears-as-list = 1\n" + " GtkTreeView::vertical-separator = 0\n" + "}\n" + //"class \"GtkComboBox\" style \"phoenix-gtk\"\n" + "class \"GtkTreeView\" style \"phoenix-gtk\"\n" + ); +} diff --git a/phoenix/gtk/platform.hpp b/phoenix/gtk/platform.hpp new file mode 100755 index 00000000..8ce3ed92 --- /dev/null +++ b/phoenix/gtk/platform.hpp @@ -0,0 +1,467 @@ +struct Settings : public configuration { + unsigned frameGeometryX; + unsigned frameGeometryY; + unsigned frameGeometryWidth; + unsigned frameGeometryHeight; + unsigned menuGeometryHeight; + unsigned statusGeometryHeight; + + void load(); + void save(); + Settings(); +}; + +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static PangoFontDescription* create(const string &description); + static void free(PangoFontDescription *font); + static Geometry geometry(PangoFontDescription *font, const string &text); + static void setFont(GtkWidget *widget, const string &font); + static void setFont(GtkWidget *widget, gpointer font); +}; + +struct pObject { + Object &object; + bool locked; + + pObject(Object &object) : object(object), locked(false) {} + virtual ~pObject() {} + + void constructor() {} + void destructor() {} +}; + +struct pOS : public pObject { + static Font defaultFont; + + static Geometry availableGeometry(); + static Geometry desktopGeometry(); + static string fileLoad(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); +}; + +struct pTimer : public pObject { + Timer &timer; + + void setEnabled(bool enabled); + void setInterval(unsigned milliseconds); + + pTimer(Timer &timer) : pObject(timer), timer(timer) {} + void constructor(); +}; + +struct pMessageWindow : public pObject { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + +struct pWindow : public pObject { + Window &window; + GtkWidget *widget; + GtkWidget *menuContainer; + GtkWidget *formContainer; + GtkWidget *statusContainer; + GtkWidget *menu; + GtkWidget *status; + GdkEventConfigure lastConfigure; + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + bool focused(); + Geometry frameMargin(); + Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFocused(); + void setFullScreen(bool fullScreen); + void setGeometry(const Geometry &geometry); + void setMenuFont(const string &font); + void setMenuVisible(bool visible); + void setResizable(bool resizable); + void setStatusFont(const string &font); + void setStatusText(const string &text); + void setStatusVisible(bool visible); + void setTitle(const string &text); + void setVisible(bool visible); + void setWidgetFont(const string &font); + + pWindow(Window &window) : pObject(window), window(window) {} + void constructor(); + unsigned menuHeight(); + unsigned statusHeight(); +}; + +struct pAction : public pObject { + Action &action; + GtkWidget *widget; + + void setEnabled(bool enabled); + void setVisible(bool visible); + + pAction(Action &action) : pObject(action), action(action) {} + void constructor(); + virtual void orphan(); + virtual void setFont(const string &font); +}; + +struct pMenu : public pAction { + Menu &menu; + GtkWidget *gtkMenu; + + void append(Action &action); + void remove(Action &action); + void setText(const string &text); + + pMenu(Menu &menu) : pAction(menu), menu(menu) {} + void constructor(); + void destructor(); + void orphan(); + void setFont(const string &font); +}; + +struct pSeparator : public pAction { + Separator &separator; + + pSeparator(Separator &separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pItem : public pAction { + Item &item; + + void setText(const string &text); + + pItem(Item &item) : pAction(item), item(item) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCheckItem : public pAction { + CheckItem &checkItem; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pRadioItem : public pAction { + RadioItem &radioItem; + + bool checked(); + void setChecked(); + void setGroup(const reference_array &group); + void setText(const string &text); + + pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { + Widget &widget; + GtkWidget *gtkWidget; + + bool enabled(); + virtual Geometry minimumGeometry(); + void setEnabled(bool enabled); + virtual void setFocused(); + virtual void setFont(const string &font); + virtual void setGeometry(const Geometry &geometry); + void setVisible(bool visible); + + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} + void constructor(); + void destructor(); + virtual void orphan(); +}; + +struct pButton : public pWidget { + Button &button; + + Geometry minimumGeometry(); + void setText(const string &text); + + pButton(Button &button) : pWidget(button), button(button) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCanvas : public pWidget { + Canvas &canvas; + cairo_surface_t *surface; + + void setSize(const Size &size); + void update(); + + pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCheckBox : public pWidget { + CheckBox &checkBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pComboBox : public pWidget { + ComboBox &comboBox; + unsigned itemCounter; + + void append(const string &text); + Geometry minimumGeometry(); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pHexEdit : public pWidget { + HexEdit &hexEdit; + GtkWidget *container; + GtkWidget *subWidget; + GtkWidget *scrollBar; + GtkTextBuffer *textBuffer; + GtkTextMark *textCursor; + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} + void constructor(); + void destructor(); + void orphan(); + unsigned cursorPosition(); + bool keyPress(unsigned scancode); + void scroll(unsigned position); + void setCursorPosition(unsigned position); + void setScroll(); + void updateScroll(); +}; + +struct pHorizontalScrollBar : public pWidget { + HorizontalScrollBar &horizontalScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pHorizontalSlider : public pWidget { + HorizontalSlider &horizontalSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLabel : public pWidget { + Label &label; + + Geometry minimumGeometry(); + void setText(const string &text); + + pLabel(Label &label) : pWidget(label), label(label) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLineEdit : public pWidget { + LineEdit &lineEdit; + + Geometry minimumGeometry(); + void setEditable(bool editable); + void setText(const string &text); + string text(); + + pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pListView : public pWidget { + ListView &listView; + GtkWidget *subWidget; + GtkListStore *store; + struct GtkColumn { + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkWidget *label; + }; + linear_vector column; + + void append(const lstring &text); + void autoSizeColumns(); + bool checked(unsigned row); + void modify(unsigned row, const lstring &text); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable); + void setChecked(unsigned row, bool checked); + void setHeaderText(const lstring &text); + void setHeaderVisible(bool visible); + void setSelected(bool selected); + void setSelection(unsigned row); + + pListView(ListView &listView) : pWidget(listView), listView(listView) {} + void constructor(); + void destructor(); + void orphan(); + void setFocused(); + void setFont(const string &font); +}; + +struct pProgressBar : public pWidget { + ProgressBar &progressBar; + + Geometry minimumGeometry(); + void setPosition(unsigned position); + + pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pRadioBox : public pWidget { + RadioBox &radioBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(); + void setGroup(const reference_array &group); + void setText(const string &text); + + pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pTextEdit : public pWidget { + TextEdit &textEdit; + GtkWidget *subWidget; + GtkTextBuffer *textBuffer; + + void setCursorPosition(unsigned position); + void setEditable(bool editable); + void setText(const string &text); + void setWordWrap(bool wordWrap); + string text(); + + pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pVerticalScrollBar : public pWidget { + VerticalScrollBar &verticalScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pVerticalSlider : public pWidget { + VerticalSlider &verticalSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pViewport : public pWidget { + Viewport &viewport; + + uintptr_t handle(); + + pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); + void destructor(); + void orphan(); +}; diff --git a/phoenix/gtk/settings.cpp b/phoenix/gtk/settings.cpp new file mode 100755 index 00000000..0905288f --- /dev/null +++ b/phoenix/gtk/settings.cpp @@ -0,0 +1,24 @@ +static Settings *settings = nullptr; + +void Settings::load() { + string path = { userpath(), ".config/phoenix/gtk.cfg" }; + configuration::load(path); +} + +void Settings::save() { + string path = { userpath(), ".config/" }; + mkdir(path, 0755); + path.append("phoenix/"); + mkdir(path, 0755); + path.append("gtk.cfg"); + configuration::save(path); +} + +Settings::Settings() { + attach(frameGeometryX = 4, "frameGeometryX"); + attach(frameGeometryY = 24, "frameGeometryY"); + attach(frameGeometryWidth = 8, "frameGeometryWidth"); + attach(frameGeometryHeight = 28, "frameGeometryHeight"); + attach(menuGeometryHeight = 20, "menuGeometryHeight"); + attach(statusGeometryHeight = 20, "statusGeometryHeight"); +} diff --git a/phoenix/gtk/timer.cpp b/phoenix/gtk/timer.cpp new file mode 100755 index 00000000..d04183f8 --- /dev/null +++ b/phoenix/gtk/timer.cpp @@ -0,0 +1,24 @@ +static guint Timer_trigger(pTimer *self) { + //timer may have been disabled prior to triggering, so check state + if(self->timer.state.enabled) { + if(self->timer.onTimeout) self->timer.onTimeout(); + } + //callback may have disabled timer, so check state again + if(self->timer.state.enabled) { + g_timeout_add(self->timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)self); + } + //kill this timer instance (it is spawned above if needed again) + return false; +} + +void pTimer::setEnabled(bool enabled) { + if(enabled) { + g_timeout_add(timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)this); + } +} + +void pTimer::setInterval(unsigned milliseconds) { +} + +void pTimer::constructor() { +} diff --git a/phoenix/gtk/widget/button.cpp b/phoenix/gtk/widget/button.cpp new file mode 100755 index 00000000..5b554fc8 --- /dev/null +++ b/phoenix/gtk/widget/button.cpp @@ -0,0 +1,28 @@ +static void Button_tick(Button *self) { + if(self->onTick) self->onTick(); +} + +Geometry pButton::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, button.state.text); + return { 0, 0, geometry.width + 24, geometry.height + 12 }; +} + +void pButton::setText(const string &text) { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); +} + +void pButton::constructor() { + gtkWidget = gtk_button_new(); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "clicked", G_CALLBACK(Button_tick), (gpointer)&button); + + setText(button.state.text); +} + +void pButton::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pButton::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/canvas.cpp b/phoenix/gtk/widget/canvas.cpp new file mode 100755 index 00000000..0231dbdb --- /dev/null +++ b/phoenix/gtk/widget/canvas.cpp @@ -0,0 +1,37 @@ +static gboolean Canvas_expose(GtkWidget *widget, GdkEvent *event, pCanvas *self) { + cairo_t *context = gdk_cairo_create(gtk_widget_get_window(widget)); + cairo_set_source_surface(context, self->surface, 0, 0); + cairo_paint(context); + cairo_destroy(context); + return true; +} + +void pCanvas::setSize(const Size &size) { + cairo_surface_destroy(surface); + surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, canvas.state.width, canvas.state.height); +} + +void pCanvas::update() { + memcpy(cairo_image_surface_get_data(surface), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + if(gtk_widget_get_realized(gtkWidget) == false) return; + gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), 0, true); +} + +void pCanvas::constructor() { + surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, canvas.state.width, canvas.state.height); + memcpy(cairo_image_surface_get_data(surface), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + gtkWidget = gtk_drawing_area_new(); + gtk_widget_set_double_buffered(gtkWidget, false); + gtk_widget_add_events(gtkWidget, GDK_EXPOSURE_MASK); + g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this); +} + +void pCanvas::destructor() { + gtk_widget_destroy(gtkWidget); + cairo_surface_destroy(surface); +} + +void pCanvas::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/check-box.cpp b/phoenix/gtk/widget/check-box.cpp new file mode 100755 index 00000000..a4a7874c --- /dev/null +++ b/phoenix/gtk/widget/check-box.cpp @@ -0,0 +1,40 @@ +static void CheckBox_tick(CheckBox *self) { + self->state.checked = self->checked(); + if(self->p.locked == false && self->onTick) self->onTick(); +} + +bool pCheckBox::checked() { + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget)); +} + +Geometry pCheckBox::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, checkBox.state.text); + return { 0, 0, geometry.width + 28, geometry.height + 4 }; +} + +void pCheckBox::setChecked(bool checked) { + locked = true; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), checked); + locked = false; +} + +void pCheckBox::setText(const string &text) { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); +} + +void pCheckBox::constructor() { + gtkWidget = gtk_check_button_new_with_label(""); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)&checkBox); + + setChecked(checkBox.state.checked); + setText(checkBox.state.text); +} + +void pCheckBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pCheckBox::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/combo-box.cpp b/phoenix/gtk/widget/combo-box.cpp new file mode 100755 index 00000000..56161b72 --- /dev/null +++ b/phoenix/gtk/widget/combo-box.cpp @@ -0,0 +1,56 @@ +static void ComboBox_change(ComboBox *self) { + if(self->p.locked == false) { + self->state.selection = self->selection(); + if(self->onChange) self->onChange(); + } +} + +void pComboBox::append(const string &text) { + gtk_combo_box_append_text(GTK_COMBO_BOX(gtkWidget), text); + if(itemCounter++ == 0) setSelection(0); +} + +Geometry pComboBox::minimumGeometry() { + unsigned maximumWidth = 0; + for(auto &item : comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(widget.state.font, item).width); + + Geometry geometry = pFont::geometry(widget.state.font, " "); + return { 0, 0, maximumWidth + 44, geometry.height + 12 }; +} + +void pComboBox::reset() { + locked = true; + gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(gtkWidget)))); + itemCounter = 0; + locked = false; +} + +unsigned pComboBox::selection() { + return gtk_combo_box_get_active(GTK_COMBO_BOX(gtkWidget)); +} + +void pComboBox::setSelection(unsigned row) { + locked = true; + gtk_combo_box_set_active(GTK_COMBO_BOX(gtkWidget), row); + locked = false; +} + +void pComboBox::constructor() { + itemCounter = 0; + gtkWidget = gtk_combo_box_new_text(); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "changed", G_CALLBACK(ComboBox_change), (gpointer)&comboBox); + + locked = true; + for(auto &text : comboBox.state.text) append(text); + locked = false; + setSelection(comboBox.state.selection); +} + +void pComboBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pComboBox::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/hex-edit.cpp b/phoenix/gtk/widget/hex-edit.cpp new file mode 100755 index 00000000..9187d33f --- /dev/null +++ b/phoenix/gtk/widget/hex-edit.cpp @@ -0,0 +1,264 @@ +static bool HexEdit_keyPress(GtkWidget *widget, GdkEventKey *event, HexEdit *self) { + return self->p.keyPress(event->keyval); +} + +static bool HexEdit_scroll(GtkRange *range, GtkScrollType scroll, gdouble value, HexEdit *self) { + self->p.scroll((unsigned)value); + return false; +} + +void pHexEdit::setColumns(unsigned columns) { + setScroll(); + update(); +} + +void pHexEdit::setLength(unsigned length) { + setScroll(); + update(); +} + +void pHexEdit::setOffset(unsigned offset) { + setScroll(); + updateScroll(); + update(); +} + +void pHexEdit::setRows(unsigned rows) { + setScroll(); + update(); +} + +void pHexEdit::update() { + if(!hexEdit.onRead) { + gtk_text_buffer_set_text(textBuffer, "", -1); + return; + } + + unsigned position = cursorPosition(); + + string output; + unsigned offset = hexEdit.state.offset; + for(unsigned row = 0; row < hexEdit.state.rows; row++) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(unsigned column = 0; column < hexEdit.state.columns; column++) { + if(offset < hexEdit.state.length) { + uint8_t data = hexEdit.onRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 }; + ansidata.append(buffer); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= hexEdit.state.length) break; + if(row != hexEdit.state.rows - 1) output.append("\n"); + } + + gtk_text_buffer_set_text(textBuffer, output, -1); + if(position == 0) position = 10; //start at first position where hex values can be entered + setCursorPosition(position); +} + +void pHexEdit::constructor() { + gtkWidget = gtk_hbox_new(false, 0); + + container = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(container), GTK_POLICY_NEVER, GTK_POLICY_NEVER); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(container), GTK_SHADOW_ETCHED_IN); + + subWidget = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), false); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_NONE); + gtk_container_add(GTK_CONTAINER(container), subWidget); + g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(HexEdit_keyPress), (gpointer)&hexEdit); + + scrollBar = gtk_vscrollbar_new((GtkAdjustment*)0); + gtk_range_set_range(GTK_RANGE(scrollBar), 0, 255); + gtk_range_set_increments(GTK_RANGE(scrollBar), 1, 16); + gtk_widget_set_sensitive(scrollBar, false); + g_signal_connect(G_OBJECT(scrollBar), "change-value", G_CALLBACK(HexEdit_scroll), (gpointer)&hexEdit); + + gtk_box_pack_start(GTK_BOX(gtkWidget), container, true, true, 0); + gtk_box_pack_start(GTK_BOX(gtkWidget), scrollBar, false, false, 1); + + textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); + textCursor = gtk_text_buffer_get_mark(textBuffer, "insert"); + + gtk_widget_show(scrollBar); + gtk_widget_show(subWidget); + gtk_widget_show(container); + + setColumns(hexEdit.state.columns); + setRows(hexEdit.state.rows); + setLength(hexEdit.state.length); + setOffset(hexEdit.state.offset); + update(); +} + +void pHexEdit::destructor() { + gtk_widget_destroy(scrollBar); + gtk_widget_destroy(subWidget); + gtk_widget_destroy(container); + gtk_widget_destroy(gtkWidget); +} + +void pHexEdit::orphan() { + destructor(); + constructor(); +} + +unsigned pHexEdit::cursorPosition() { + GtkTextIter iter; + gtk_text_buffer_get_iter_at_mark(textBuffer, &iter, textCursor); + return gtk_text_iter_get_offset(&iter); +} + +bool pHexEdit::keyPress(unsigned scancode) { + if(!hexEdit.onRead) return false; + + unsigned position = cursorPosition(); + unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1; + unsigned cursorY = position / lineWidth; + unsigned cursorX = position % lineWidth; + + if(scancode == GDK_KEY_Home) { + setCursorPosition(cursorY * lineWidth + 10); + return true; + } + + if(scancode == GDK_KEY_End) { + setCursorPosition(cursorY * lineWidth + 10 + (hexEdit.state.columns * 3 - 1)); + return true; + } + + if(scancode == GDK_KEY_Up) { + if(cursorY != 0) return false; + + signed newOffset = hexEdit.state.offset - hexEdit.state.columns; + if(newOffset >= 0) { + hexEdit.setOffset(newOffset); + update(); + } + return true; + } + + if(scancode == GDK_KEY_Down) { + if(cursorY != hexEdit.state.rows - 1) return false; + + signed newOffset = hexEdit.state.offset + hexEdit.state.columns; + if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) { + hexEdit.setOffset(newOffset); + update(); + } + return true; + } + + if(scancode == GDK_KEY_Page_Up) { + signed newOffset = hexEdit.state.offset - hexEdit.state.columns * hexEdit.state.rows; + if(newOffset >= 0) { + hexEdit.setOffset(newOffset); + } else { + hexEdit.setOffset(0); + } + update(); + return true; + } + + if(scancode == GDK_KEY_Page_Down) { + signed newOffset = hexEdit.state.offset + hexEdit.state.columns * hexEdit.state.rows; + for(unsigned n = 0; n < hexEdit.state.rows; n++) { + if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) { + hexEdit.setOffset(newOffset); + update(); + break; + } + newOffset -= hexEdit.state.columns; + } + return true; + } + + //convert scancode to hex nibble + if(scancode >= '0' && scancode <= '9') scancode = scancode - '0'; + else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10; + else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10; + else return false; //not a valid hex value + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < hexEdit.state.columns) { + //not in ANSI region + unsigned offset = hexEdit.state.offset + (cursorY * hexEdit.state.columns + cursorX); + + if(offset >= hexEdit.state.length) return false; //do not edit past end of data + uint8_t data = hexEdit.onRead(offset); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (scancode << 0); + } else { + data = (data & 0x0f) | (scancode << 4); + } + if(hexEdit.onWrite) hexEdit.onWrite(offset, data); + + //auto-advance cursor to next nibble/byte + position++; + if(cursorNibble && cursorX != hexEdit.state.columns - 1) position++; + setCursorPosition(position); + + //refresh output to reflect modified data + update(); + } + } + } + + return true; +} + +void pHexEdit::scroll(unsigned position) { + unsigned rows = hexEdit.state.length / hexEdit.state.columns; + if(position >= rows) position = rows - 1; + hexEdit.setOffset(position * hexEdit.state.columns); +} + +void pHexEdit::setCursorPosition(unsigned position) { + GtkTextIter iter; + gtk_text_buffer_get_iter_at_mark(textBuffer, &iter, textCursor); + + //GTK+ will throw many errors to the terminal if you set iterator past end of buffer + GtkTextIter endIter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + unsigned endPosition = gtk_text_iter_get_offset(&iter); + + gtk_text_iter_set_offset(&iter, min(position, endPosition)); + gtk_text_buffer_place_cursor(textBuffer, &iter); +} + +void pHexEdit::setScroll() { + unsigned rows = hexEdit.state.length / hexEdit.state.columns; + if(rows) rows--; + if(rows) { + gtk_range_set_range(GTK_RANGE(scrollBar), 0, rows); + gtk_widget_set_sensitive(scrollBar, true); + } else { + gtk_widget_set_sensitive(scrollBar, false); + } +} + +void pHexEdit::updateScroll() { + unsigned row = hexEdit.state.offset / hexEdit.state.columns; + gtk_range_set_value(GTK_RANGE(scrollBar), row); +} diff --git a/phoenix/gtk/widget/horizontal-scroll-bar.cpp b/phoenix/gtk/widget/horizontal-scroll-bar.cpp new file mode 100755 index 00000000..4e265f4c --- /dev/null +++ b/phoenix/gtk/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,40 @@ +static void HorizontalScrollBar_change(HorizontalScrollBar *self) { + if(self->state.position == self->position()) return; + self->state.position = self->position(); + if(self->onChange) self->onChange(); +} + +Geometry pHorizontalScrollBar::minimumGeometry() { + return { 0, 0, 0, 20 }; +} + +unsigned pHorizontalScrollBar::position() { + return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget)); +} + +void pHorizontalScrollBar::setLength(unsigned length) { + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); +} + +void pHorizontalScrollBar::setPosition(unsigned position) { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +void pHorizontalScrollBar::constructor() { + gtkWidget = gtk_hscrollbar_new(0); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalScrollBar_change), (gpointer)&horizontalScrollBar); + + setLength(horizontalScrollBar.state.length); + setPosition(horizontalScrollBar.state.position); +} + +void pHorizontalScrollBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/horizontal-slider.cpp b/phoenix/gtk/widget/horizontal-slider.cpp new file mode 100755 index 00000000..9913d72d --- /dev/null +++ b/phoenix/gtk/widget/horizontal-slider.cpp @@ -0,0 +1,41 @@ +static void HorizontalSlider_change(HorizontalSlider *self) { + if(self->state.position == self->position()) return; + self->state.position = self->position(); + if(self->onChange) self->onChange(); +} + +Geometry pHorizontalSlider::minimumGeometry() { + return { 0, 0, 0, 20 }; +} + +unsigned pHorizontalSlider::position() { + return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget)); +} + +void pHorizontalSlider::setLength(unsigned length) { + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); +} + +void pHorizontalSlider::setPosition(unsigned position) { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +void pHorizontalSlider::constructor() { + gtkWidget = gtk_hscale_new_with_range(0, 100, 1); + gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)&horizontalSlider); + + setLength(horizontalSlider.state.length); + setPosition(horizontalSlider.state.position); +} + +void pHorizontalSlider::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/label.cpp b/phoenix/gtk/widget/label.cpp new file mode 100755 index 00000000..8b5cec4f --- /dev/null +++ b/phoenix/gtk/widget/label.cpp @@ -0,0 +1,24 @@ +Geometry pLabel::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, label.state.text); + return { 0, 0, geometry.width, geometry.height }; +} + +void pLabel::setText(const string &text) { + gtk_label_set_text(GTK_LABEL(gtkWidget), text); +} + +void pLabel::constructor() { + gtkWidget = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(gtkWidget), 0.0, 0.5); + + setText(label.state.text); +} + +void pLabel::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pLabel::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/line-edit.cpp b/phoenix/gtk/widget/line-edit.cpp new file mode 100755 index 00000000..8dbe9ef4 --- /dev/null +++ b/phoenix/gtk/widget/line-edit.cpp @@ -0,0 +1,45 @@ +static void LineEdit_activate(LineEdit *self) { + if(self->onActivate) self->onActivate(); +} + +static void LineEdit_change(LineEdit *self) { + self->state.text = self->text(); + if(self->p.locked == false && self->onChange) self->onChange(); +} + +Geometry pLineEdit::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, lineEdit.state.text); + return { 0, 0, geometry.width + 10, geometry.height + 10 }; +} + +void pLineEdit::setEditable(bool editable) { + gtk_editable_set_editable(GTK_EDITABLE(gtkWidget), editable); +} + +void pLineEdit::setText(const string &text) { + locked = true; + gtk_entry_set_text(GTK_ENTRY(gtkWidget), text); + locked = false; +} + +string pLineEdit::text() { + return gtk_entry_get_text(GTK_ENTRY(gtkWidget)); +} + +void pLineEdit::constructor() { + gtkWidget = gtk_entry_new(); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "activate", G_CALLBACK(LineEdit_activate), (gpointer)&lineEdit); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "changed", G_CALLBACK(LineEdit_change), (gpointer)&lineEdit); + + setEditable(lineEdit.state.editable); + setText(lineEdit.state.text); +} + +void pLineEdit::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pLineEdit::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/list-view.cpp b/phoenix/gtk/widget/list-view.cpp new file mode 100755 index 00000000..83efaaaa --- /dev/null +++ b/phoenix/gtk/widget/list-view.cpp @@ -0,0 +1,216 @@ +static void ListView_activate(ListView *self) { + if(self->onActivate) self->onActivate(); +} + +static void ListView_change(ListView *self) { + if(self->state.selected == false || self->state.selection != self->selection()) { + self->state.selected = true; + self->state.selection = self->selection(); + if(self->onChange) self->onChange(); + } +} + +static void ListView_tick(GtkCellRendererToggle *cell, gchar *path_string, ListView *self) { + unsigned row = decimal(path_string); + self->setChecked(row, !self->checked(row)); + if(self->onTick) self->onTick(row); +} + +void pListView::append(const lstring &text) { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n, (const char*)text[n], -1); +} + +void pListView::autoSizeColumns() { + gtk_tree_view_columns_autosize(GTK_TREE_VIEW(subWidget)); +} + +bool pListView::checked(unsigned row) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreePath *path = gtk_tree_path_new_from_string(string(row)); + GtkTreeIter iter; + bool state; + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, 0, &state, -1); + gtk_tree_path_free(path); + return state; +} + +void pListView::modify(unsigned row, const lstring &text) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + for(unsigned i = 0; i <= row; i++) { + if(i == 0) gtk_tree_model_get_iter_first(model, &iter); + else gtk_tree_model_iter_next(model, &iter); + } + for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n, (const char*)text[n], -1); +} + +void pListView::reset() { + listView.state.selected = false; + listView.state.selection = 0; + gtk_list_store_clear(GTK_LIST_STORE(store)); + gtk_tree_view_set_model(GTK_TREE_VIEW(subWidget), GTK_TREE_MODEL(store)); + //reset gtk_scrolled_window scrollbar position to 0,0 (top-left), as ListView is now empty + gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(gtkWidget), 0); + gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(gtkWidget), 0); +} + +bool pListView::selected() { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + if(gtk_tree_model_get_iter_first(model, &iter) == false) return false; + if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return true; + for(unsigned n = 1;; n++) { + if(gtk_tree_model_iter_next(model, &iter) == false) return false; + if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return true; + } + return false; +} + +unsigned pListView::selection() { + if(selected() == false) return listView.state.selection; + + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreeIter iter; + if(gtk_tree_model_get_iter_first(model, &iter) == false) return 0; + if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return 0; + for(unsigned n = 1;; n++) { + if(gtk_tree_model_iter_next(model, &iter) == false) return 0; + if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return n; + } + return 0; +} + +void pListView::setCheckable(bool checkable) { + gtk_tree_view_column_set_visible(column[0].column, checkable); +} + +void pListView::setChecked(unsigned row, bool checked) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + GtkTreePath *path = gtk_tree_path_new_from_string(string(row)); + GtkTreeIter iter; + gtk_tree_model_get_iter(model, &iter, path); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, checked, -1); + gtk_tree_path_free(path); +} + +void pListView::setHeaderText(const lstring &text) { + destructor(); + constructor(); +} + +void pListView::setHeaderVisible(bool visible) { + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(subWidget), visible); +} + +void pListView::setSelected(bool selected) { + if(selected == false) { + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); + gtk_tree_selection_unselect_all(selection); + } else { + setSelection(listView.state.selection); + } +} + +void pListView::setSelection(unsigned row) { + signed current = -1; + if(selected()) current = selection(); + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); + gtk_tree_selection_unselect_all(selection); + + GtkTreeIter iter; + if(gtk_tree_model_get_iter_first(model, &iter) == false) return; + if(row == 0) { + gtk_tree_selection_select_iter(selection, &iter); + return; + } + for(unsigned n = 1;; n++) { + if(gtk_tree_model_iter_next(model, &iter) == false) return; + if(row == n) { + gtk_tree_selection_select_iter(selection, &iter); + return; + } + } +} + +void pListView::constructor() { + gtkWidget = 0; + subWidget = 0; + + gtkWidget = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); + + lstring headerText; + headerText.append(""); //checkbox column + for(auto &headerItem : listView.state.headerText) headerText.append(headerItem); + if(headerText.size() == 1) headerText.append(""); + + GType *v = (GType*)malloc(headerText.size() * sizeof(GType)); + for(unsigned n = 0; n < headerText.size(); n++) v[n] = (n == 0 ? G_TYPE_BOOLEAN : G_TYPE_STRING); + store = gtk_list_store_newv(headerText.size(), v); + free(v); + + subWidget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); + g_object_unref(G_OBJECT(store)); + + for(unsigned n = 0; n < headerText.size(); n++) { + if(n == 0) { + column[n].renderer = gtk_cell_renderer_toggle_new(); + column[n].column = gtk_tree_view_column_new_with_attributes("", column[n].renderer, "active", n, (void*)0); + gtk_tree_view_column_set_resizable(column[n].column, false); + gtk_tree_view_column_set_visible(column[n].column, false); + g_signal_connect(column[n].renderer, "toggled", G_CALLBACK(ListView_tick), (gpointer)&listView); + } else { + column[n].renderer = gtk_cell_renderer_text_new(); + column[n].column = gtk_tree_view_column_new_with_attributes("", column[n].renderer, "text", n, (void*)0); + gtk_tree_view_column_set_resizable(column[n].column, true); + } + column[n].label = gtk_label_new(headerText[n]); + gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(column[n].column), column[n].label); + gtk_tree_view_append_column(GTK_TREE_VIEW(subWidget), column[n].column); + gtk_widget_show(column[n].label); + } + + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(subWidget), headerText.size() >= 3); //two or more columns + checkbox column + gtk_tree_view_set_search_column(GTK_TREE_VIEW(subWidget), 1); + + g_signal_connect_swapped(G_OBJECT(subWidget), "cursor-changed", G_CALLBACK(ListView_change), (gpointer)&listView); + g_signal_connect_swapped(G_OBJECT(subWidget), "row-activated", G_CALLBACK(ListView_activate), (gpointer)&listView); + + gtk_widget_show(subWidget); + + setHeaderVisible(listView.state.headerVisible); + setCheckable(listView.state.checkable); + for(auto &text : listView.state.text) append(text); + for(unsigned n = 0; n < listView.state.checked.size(); n++) setChecked(n, listView.state.checked[n]); + if(listView.state.selected) setSelection(listView.state.selection); + autoSizeColumns(); +} + +void pListView::destructor() { + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +void pListView::orphan() { + destructor(); + constructor(); +} + +void pListView::setFocused() { + gtk_widget_grab_focus(subWidget); +} + +void pListView::setFont(const string &font) { + pFont::setFont(gtkWidget, font); + for(unsigned n = 0; n < 1 + listView.state.headerText.size(); n++) { + pFont::setFont(column[n].label, font); + } +} diff --git a/phoenix/gtk/widget/progress-bar.cpp b/phoenix/gtk/widget/progress-bar.cpp new file mode 100755 index 00000000..972170b8 --- /dev/null +++ b/phoenix/gtk/widget/progress-bar.cpp @@ -0,0 +1,23 @@ +Geometry pProgressBar::minimumGeometry() { + return { 0, 0, 0, 25 }; +} + +void pProgressBar::setPosition(unsigned position) { + position = position <= 100 ? position : 0; + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkWidget), (double)position / 100.0); +} + +void pProgressBar::constructor() { + gtkWidget = gtk_progress_bar_new(); + + setPosition(progressBar.state.position); +} + +void pProgressBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pProgressBar::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/radio-box.cpp b/phoenix/gtk/widget/radio-box.cpp new file mode 100755 index 00000000..02e86b4f --- /dev/null +++ b/phoenix/gtk/widget/radio-box.cpp @@ -0,0 +1,50 @@ +static void RadioBox_tick(RadioBox *self) { + if(self->p.locked == false && self->checked() && self->onTick) self->onTick(); +} + +bool pRadioBox::checked() { + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget)); +} + +Geometry pRadioBox::minimumGeometry() { + Geometry geometry = pFont::geometry(widget.state.font, radioBox.state.text); +//Font &font = pWidget::font(); +//Geometry geometry = font.geometry(radioBox.state.text); + return { 0, 0, geometry.width + 28, geometry.height + 4 }; +} + +void pRadioBox::setChecked() { + locked = true; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), true); + locked = false; +} + +void pRadioBox::setGroup(const reference_array &group) { + for(unsigned n = 0; n < group.size(); n++) { + if(n == 0) continue; + GSList *currentGroup = gtk_radio_button_get_group(GTK_RADIO_BUTTON(group[0].p.gtkWidget)); + if(currentGroup != gtk_radio_button_get_group(GTK_RADIO_BUTTON(gtkWidget))) { + gtk_radio_button_set_group(GTK_RADIO_BUTTON(gtkWidget), currentGroup); + } + } +} + +void pRadioBox::setText(const string &text) { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); +} + +void pRadioBox::constructor() { + gtkWidget = gtk_radio_button_new_with_label(0, ""); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)&radioBox); + + setText(radioBox.state.text); +} + +void pRadioBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pRadioBox::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/text-edit.cpp b/phoenix/gtk/widget/text-edit.cpp new file mode 100755 index 00000000..a1803bbf --- /dev/null +++ b/phoenix/gtk/widget/text-edit.cpp @@ -0,0 +1,63 @@ +static void TextEdit_change(TextEdit *self) { + self->state.text = self->text(); + if(self->p.locked == false && self->onChange) self->onChange(); +} + +void pTextEdit::setCursorPosition(unsigned position) { + GtkTextMark *mark = gtk_text_buffer_get_mark(textBuffer, "insert"); + GtkTextIter iter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + gtk_text_iter_set_offset(&iter, min(position, gtk_text_iter_get_offset(&iter))); + gtk_text_buffer_place_cursor(textBuffer, &iter); + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark); +} + +void pTextEdit::setEditable(bool editable) { + gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), editable); +} + +void pTextEdit::setText(const string &text) { + locked = true; + gtk_text_buffer_set_text(textBuffer, text, -1); + locked = false; +} + +void pTextEdit::setWordWrap(bool wordWrap) { + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), wordWrap ? GTK_WRAP_WORD_CHAR : GTK_WRAP_NONE); +} + +string pTextEdit::text() { + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(textBuffer, &start); + gtk_text_buffer_get_end_iter(textBuffer, &end); + char *temp = gtk_text_buffer_get_text(textBuffer, &start, &end, true); + string text = temp; + g_free(temp); + return text; +} + +void pTextEdit::constructor() { + gtkWidget = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); + subWidget = gtk_text_view_new(); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_WORD_CHAR); + gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); + textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); + g_signal_connect_swapped(G_OBJECT(textBuffer), "changed", G_CALLBACK(TextEdit_change), (gpointer)&textEdit); + gtk_widget_show(subWidget); + + setEditable(textEdit.state.editable); + setText(textEdit.state.text); + setWordWrap(textEdit.state.wordWrap); +} + +void pTextEdit::destructor() { + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +void pTextEdit::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/vertical-scroll-bar.cpp b/phoenix/gtk/widget/vertical-scroll-bar.cpp new file mode 100755 index 00000000..5eedbc5b --- /dev/null +++ b/phoenix/gtk/widget/vertical-scroll-bar.cpp @@ -0,0 +1,40 @@ +static void VerticalScrollBar_change(VerticalScrollBar *self) { + if(self->state.position == self->position()) return; + self->state.position = self->position(); + if(self->onChange) self->onChange(); +} + +Geometry pVerticalScrollBar::minimumGeometry() { + return { 0, 0, 20, 0 }; +} + +unsigned pVerticalScrollBar::position() { + return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget)); +} + +void pVerticalScrollBar::setLength(unsigned length) { + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); +} + +void pVerticalScrollBar::setPosition(unsigned position) { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +void pVerticalScrollBar::constructor() { + gtkWidget = gtk_vscrollbar_new(0); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalScrollBar_change), (gpointer)&verticalScrollBar); + + setLength(verticalScrollBar.state.length); + setPosition(verticalScrollBar.state.position); +} + +void pVerticalScrollBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/vertical-slider.cpp b/phoenix/gtk/widget/vertical-slider.cpp new file mode 100755 index 00000000..b1148410 --- /dev/null +++ b/phoenix/gtk/widget/vertical-slider.cpp @@ -0,0 +1,41 @@ +static void VerticalSlider_change(VerticalSlider *self) { + if(self->state.position == self->position()) return; + self->state.position = self->position(); + if(self->onChange) self->onChange(); +} + +Geometry pVerticalSlider::minimumGeometry() { + return { 0, 0, 20, 0 }; +} + +unsigned pVerticalSlider::position() { + return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget)); +} + +void pVerticalSlider::setLength(unsigned length) { + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); +} + +void pVerticalSlider::setPosition(unsigned position) { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +void pVerticalSlider::constructor() { + gtkWidget = gtk_vscale_new_with_range(0, 100, 1); + gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); + g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)&verticalSlider); + + setLength(verticalSlider.state.length); + setPosition(verticalSlider.state.position); +} + +void pVerticalSlider::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/viewport.cpp b/phoenix/gtk/widget/viewport.cpp new file mode 100755 index 00000000..18c61f5b --- /dev/null +++ b/phoenix/gtk/widget/viewport.cpp @@ -0,0 +1,24 @@ +uintptr_t pViewport::handle() { + return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget)); +} + +void pViewport::constructor() { + gtkWidget = gtk_drawing_area_new(); +//gtk_widget_set_double_buffered(gtkWidget, false); + + GdkColor color; + color.pixel = 0; + color.red = 0; + color.green = 0; + color.blue = 0; + gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color); +} + +void pViewport::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pViewport::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/widget/widget.cpp b/phoenix/gtk/widget/widget.cpp new file mode 100755 index 00000000..dceb8266 --- /dev/null +++ b/phoenix/gtk/widget/widget.cpp @@ -0,0 +1,47 @@ +Geometry pWidget::minimumGeometry() { + return { 0, 0, 0, 0 }; +} + +bool pWidget::enabled() { + return gtk_widget_get_sensitive(gtkWidget); +} + +void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; + gtk_widget_set_sensitive(gtkWidget, enabled); +} + +void pWidget::setFocused() { + gtk_widget_grab_focus(gtkWidget); +} + +void pWidget::setFont(const string &font) { + pFont::setFont(gtkWidget, font); +} + +void pWidget::setGeometry(const Geometry &geometry) { + if(sizable.window() && sizable.window()->visible()) gtk_fixed_move(GTK_FIXED(sizable.window()->p.formContainer), gtkWidget, geometry.x, geometry.y); + unsigned width = (signed)geometry.width <= 0 ? 1U : geometry.width; + unsigned height = (signed)geometry.height <= 0 ? 1U : geometry.height; + gtk_widget_set_size_request(gtkWidget, width, height); +} + +void pWidget::setVisible(bool visible) { + if(widget.state.abstract) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; + gtk_widget_set_visible(gtkWidget, visible); +} + +void pWidget::constructor() { + if(widget.state.abstract) gtkWidget = gtk_label_new(""); +} + +void pWidget::destructor() { + if(widget.state.abstract) gtk_widget_destroy(gtkWidget); +} + +void pWidget::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/gtk/window.cpp b/phoenix/gtk/window.cpp new file mode 100755 index 00000000..7d20bd85 --- /dev/null +++ b/phoenix/gtk/window.cpp @@ -0,0 +1,280 @@ +static gint Window_close(GtkWidget *widget, GdkEvent *event, Window *window) { + window->state.ignore = false; + if(window->onClose) window->onClose(); + if(window->state.ignore == false) window->setVisible(false); + return true; +} + +static gboolean Window_expose(GtkWidget *widget, GdkEvent *event, Window *window) { + cairo_t *context = gdk_cairo_create(widget->window); + + Color color = window->backgroundColor(); + double red = (double)color.red / 255.0; + double green = (double)color.green / 255.0; + double blue = (double)color.blue / 255.0; + double alpha = (double)color.alpha / 255.0; + + if(gdk_screen_is_composited(gdk_screen_get_default())) { + cairo_set_source_rgba(context, red, green, blue, alpha); + } else { + cairo_set_source_rgb(context, red, green, blue); + } + + cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); + cairo_paint(context); + cairo_destroy(context); + + return false; +} + +static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *window) { + if(gtk_widget_get_realized(window->p.widget) == false) return false; + GdkWindow *gdkWindow = gtk_widget_get_window(widget); + + GdkRectangle border, client; + gdk_window_get_frame_extents(gdkWindow, &border); + gdk_window_get_geometry(gdkWindow, 0, 0, &client.width, &client.height, 0); + gdk_window_get_origin(gdkWindow, &client.x, &client.y); + + if(window->state.fullScreen == false) { + //update geometry settings + settings->frameGeometryX = client.x - border.x; + settings->frameGeometryY = client.y - border.y; + settings->frameGeometryWidth = border.width - client.width; + settings->frameGeometryHeight = border.height - client.height; + } + + //move + if(event->configure.x != window->p.lastConfigure.x + || event->configure.y != window->p.lastConfigure.y + ) { + if(window->state.fullScreen == false) { + window->state.geometry.x = client.x; + window->state.geometry.y = client.y + window->p.menuHeight(); + } + if(window->p.locked == false && window->onMove) window->onMove(); + } + + //size + if(event->configure.width != window->p.lastConfigure.width + || event->configure.height != window->p.lastConfigure.height + ) { + if(window->state.fullScreen == false) { + window->state.geometry.width = client.width; + window->state.geometry.height = client.height - window->p.menuHeight() - window->p.statusHeight(); + } + + for(auto &layout : window->state.layout) { + Geometry geometry = window->geometry(); + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); + } + + if(window->p.locked == false && window->onSize) window->onSize(); + } + + window->p.lastConfigure = event->configure; + return false; +} + +void pWindow::append(Layout &layout) { + Geometry geometry = this->geometry(); + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); +} + +void pWindow::append(Menu &menu) { + if(window.state.menuFont != "") menu.p.setFont(window.state.menuFont); + else menu.p.setFont("Sans, 8"); + gtk_menu_shell_append(GTK_MENU_SHELL(this->menu), menu.p.widget); + gtk_widget_show(menu.p.widget); +} + +void pWindow::append(Widget &widget) { + ((Sizable&)widget).state.window = &window; + gtk_fixed_put(GTK_FIXED(formContainer), widget.p.gtkWidget, 0, 0); + if(widget.state.font != "") widget.p.setFont(widget.state.font); + else if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Sans, 8"); + widget.setVisible(widget.visible()); +} + +Color pWindow::backgroundColor() { + if(window.state.backgroundColorOverride) return window.state.backgroundColor; + GdkColor color = widget->style->bg[GTK_STATE_NORMAL]; + return { (uint8_t)(color.red >> 8), (uint8_t)(color.green >> 8), (uint8_t)(color.blue >> 8), 255 }; +} + +Geometry pWindow::frameMargin() { + if(window.state.fullScreen) return { 0, menuHeight(), 0, menuHeight() + statusHeight() }; + return { + settings->frameGeometryX, + settings->frameGeometryY + menuHeight(), + settings->frameGeometryWidth, + settings->frameGeometryHeight + menuHeight() + statusHeight() + }; +} + +bool pWindow::focused() { + return gtk_window_is_active(GTK_WINDOW(widget)); +} + +Geometry pWindow::geometry() { + if(window.state.fullScreen == true) { + return { 0, menuHeight(), OS::desktopGeometry().width, OS::desktopGeometry().height - menuHeight() - statusHeight() }; + }; + return window.state.geometry; +} + +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + menu.p.orphan(); +} + +void pWindow::remove(Widget &widget) { + widget.p.orphan(); +} + +void pWindow::setBackgroundColor(const Color &color) { + GdkColor gdkColor; + gdkColor.pixel = (color.red << 16) | (color.green << 8) | (color.blue << 0); + gdkColor.red = (color.red << 8) | (color.red << 0); + gdkColor.green = (color.green << 8) | (color.green << 0); + gdkColor.blue = (color.blue << 8) | (color.blue << 0); + gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &gdkColor); +} + +void pWindow::setFocused() { + gtk_window_present(GTK_WINDOW(widget)); +} + +void pWindow::setFullScreen(bool fullScreen) { + if(fullScreen == false) { + gtk_window_unfullscreen(GTK_WINDOW(widget)); + gtk_window_set_resizable(GTK_WINDOW(widget), window.state.resizable); + gtk_window_set_decorated(GTK_WINDOW(widget), true); + gtk_widget_set_size_request(widget, -1, -1); + gdk_display_sync(gtk_widget_get_display(widget)); + setGeometry(window.state.geometry); + } else { + gtk_window_fullscreen(GTK_WINDOW(widget)); + gtk_window_set_decorated(GTK_WINDOW(widget), false); + gtk_widget_set_size_request(widget, OS::desktopGeometry().width, OS::desktopGeometry().height); + gtk_window_set_resizable(GTK_WINDOW(widget), false); + } + gdk_display_sync(gtk_widget_get_display(widget)); +} + +void pWindow::setGeometry(const Geometry &geometry) { + OS::processEvents(); + + Geometry margin = frameMargin(); + gtk_window_move(GTK_WINDOW(widget), geometry.x - margin.x, geometry.y - margin.y); + +//GdkGeometry geom; +//geom.min_width = 1; +//geom.min_height = 1; +//gtk_window_set_geometry_hints(GTK_WINDOW(widget), GTK_WIDGET(widget), &geom, GDK_HINT_MIN_SIZE); + + gtk_window_set_policy(GTK_WINDOW(widget), true, true, false); + gtk_widget_set_size_request(formContainer, geometry.width, geometry.height); + gtk_window_resize(GTK_WINDOW(widget), geometry.width, geometry.height + menuHeight() + statusHeight()); + + for(auto &layout : window.state.layout) { + Geometry geometry = this->geometry(); + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); + } +} + +void pWindow::setMenuFont(const string &font) { + for(auto &item : window.state.menu) item.p.setFont(font); +} + +void pWindow::setMenuVisible(bool visible) { + gtk_widget_set_visible(menu, visible); +} + +void pWindow::setResizable(bool resizable) { + gtk_window_set_resizable(GTK_WINDOW(widget), resizable); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), resizable); +} + +void pWindow::setStatusFont(const string &font) { + pFont::setFont(status, font); +} + +void pWindow::setStatusText(const string &text) { + gtk_statusbar_pop(GTK_STATUSBAR(status), 1); + gtk_statusbar_push(GTK_STATUSBAR(status), 1, text); +} + +void pWindow::setStatusVisible(bool visible) { + gtk_widget_set_visible(status, visible); +} + +void pWindow::setTitle(const string &text) { + gtk_window_set_title(GTK_WINDOW(widget), text); +} + +void pWindow::setVisible(bool visible) { + gtk_widget_set_visible(widget, visible); +} + +void pWindow::setWidgetFont(const string &font) { + for(auto &item : window.state.widget) { + if(item.state.font == "") item.setFont(font); + } +} + +void pWindow::constructor() { + memset(&lastConfigure, 0, sizeof(GdkEventConfigure)); + widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + if(gdk_screen_is_composited(gdk_screen_get_default())) { + gtk_widget_set_colormap(widget, gdk_screen_get_rgba_colormap(gdk_screen_get_default())); + } else { + gtk_widget_set_colormap(widget, gdk_screen_get_rgb_colormap(gdk_screen_get_default())); + } + + gtk_window_set_resizable(GTK_WINDOW(widget), true); + gtk_widget_set_app_paintable(widget, true); + gtk_widget_add_events(widget, GDK_CONFIGURE); + + menuContainer = gtk_vbox_new(false, 0); + gtk_container_add(GTK_CONTAINER(widget), menuContainer); + gtk_widget_show(menuContainer); + + menu = gtk_menu_bar_new(); + gtk_box_pack_start(GTK_BOX(menuContainer), menu, false, false, 0); + + formContainer = gtk_fixed_new(); + gtk_box_pack_start(GTK_BOX(menuContainer), formContainer, true, true, 0); + gtk_widget_show(formContainer); + + statusContainer = gtk_event_box_new(); + status = gtk_statusbar_new(); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), true); + gtk_container_add(GTK_CONTAINER(statusContainer), status); + gtk_box_pack_start(GTK_BOX(menuContainer), statusContainer, false, false, 0); + gtk_widget_show(statusContainer); + + setTitle(""); + setGeometry(window.state.geometry); + setMenuFont("Sans, 8"); + setStatusFont("Sans, 8"); + + g_signal_connect(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window); + g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(Window_expose), (gpointer)&window); + g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window); +} + +unsigned pWindow::menuHeight() { + return window.state.menuVisible ? settings->menuGeometryHeight : 0; +} + +unsigned pWindow::statusHeight() { + return window.state.statusVisible ? settings->statusGeometryHeight : 0; +} diff --git a/phoenix/phoenix.cpp b/phoenix/phoenix.cpp new file mode 100755 index 00000000..1aa709fb --- /dev/null +++ b/phoenix/phoenix.cpp @@ -0,0 +1,46 @@ +#ifndef PHOENIX_CPP +#define PHOENIX_CPP + +#if defined(PHOENIX_WINDOWS) + #define UNICODE + #define WINVER 0x0501 + #define _WIN32_WINNT 0x0501 + #define _WIN32_IE 0x0600 + #define __MSVCRT_VERSION__ 0x0601 + #define NOMINMAX + + #include + #include + #include + #include + #include +#elif defined(PHOENIX_QT) + #include + #include +#elif defined(PHOENIX_GTK) + #define None + #define Window X11Window + #define X11None 0L + + #include + #include + #include + #include + #include + #include + + #undef None + #undef Window +#elif defined(PHOENIX_REFERENCE) +#else + #error "phoenix: unrecognized target" +#endif + +#include "phoenix.hpp" +using namespace nall; + +namespace phoenix { + #include "core/core.cpp" +} + +#endif diff --git a/phoenix/phoenix.hpp b/phoenix/phoenix.hpp new file mode 100755 index 00000000..24ffa185 --- /dev/null +++ b/phoenix/phoenix.hpp @@ -0,0 +1,19 @@ +#ifndef PHOENIX_HPP +#define PHOENIX_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace phoenix { + #include "core/core.hpp" +} + +#endif diff --git a/phoenix/qt/action/action.cpp b/phoenix/qt/action/action.cpp new file mode 100755 index 00000000..62efaa2a --- /dev/null +++ b/phoenix/qt/action/action.cpp @@ -0,0 +1,49 @@ +void pAction::setEnabled(bool enabled) { + if(dynamic_cast(&action)) { + ((Menu&)action).p.qtMenu->setEnabled(enabled); + } else if(dynamic_cast(&action)) { + ((Separator&)action).p.qtAction->setEnabled(enabled); + } else if(dynamic_cast(&action)) { + ((Item&)action).p.qtAction->setEnabled(enabled); + } else if(dynamic_cast(&action)) { + ((CheckItem&)action).p.qtAction->setEnabled(enabled); + } else if(dynamic_cast(&action)) { + ((RadioItem&)action).p.qtAction->setEnabled(enabled); + } +} + +void pAction::setFont(const string &font) { + QFont qtFont = pFont::create(font); + + if(dynamic_cast(&action)) { + ((Menu&)action).p.setFont(font); + } else if(dynamic_cast(&action)) { + ((Separator&)action).p.qtAction->setFont(qtFont); + } else if(dynamic_cast(&action)) { + ((Item&)action).p.qtAction->setFont(qtFont); + } else if(dynamic_cast(&action)) { + ((CheckItem&)action).p.qtAction->setFont(qtFont); + } else if(dynamic_cast(&action)) { + ((RadioItem&)action).p.qtAction->setFont(qtFont); + } +} + +void pAction::setVisible(bool visible) { + if(dynamic_cast(&action)) { + ((Menu&)action).p.qtMenu->menuAction()->setVisible(visible); + } else if(dynamic_cast(&action)) { + ((Separator&)action).p.qtAction->setVisible(visible); + } else if(dynamic_cast(&action)) { + ((Item&)action).p.qtAction->setVisible(visible); + } else if(dynamic_cast(&action)) { + ((CheckItem&)action).p.qtAction->setVisible(visible); + } else if(dynamic_cast(&action)) { + ((RadioItem&)action).p.qtAction->setVisible(visible); + } +} + +void pAction::constructor() { +} + +void pAction::destructor() { +} diff --git a/phoenix/qt/action/check-item.cpp b/phoenix/qt/action/check-item.cpp new file mode 100755 index 00000000..7c18d836 --- /dev/null +++ b/phoenix/qt/action/check-item.cpp @@ -0,0 +1,27 @@ +bool pCheckItem::checked() { + return qtAction->isChecked(); +} + +void pCheckItem::setChecked(bool checked) { + qtAction->setChecked(checked); +} + +void pCheckItem::setText(const string &text) { + qtAction->setText(QString::fromUtf8(text)); +} + +void pCheckItem::constructor() { + qtAction = new QAction(0); + qtAction->setCheckable(true); + connect(qtAction, SIGNAL(triggered()), SLOT(onTick())); +} + +void pCheckItem::destructor() { + if(action.state.menu) action.state.menu->remove(checkItem); + delete qtAction; +} + +void pCheckItem::onTick() { + checkItem.state.checked = checked(); + if(checkItem.onTick) checkItem.onTick(); +} diff --git a/phoenix/qt/action/item.cpp b/phoenix/qt/action/item.cpp new file mode 100755 index 00000000..9a9daec7 --- /dev/null +++ b/phoenix/qt/action/item.cpp @@ -0,0 +1,17 @@ +void pItem::setText(const string &text) { + qtAction->setText(QString::fromUtf8(text)); +} + +void pItem::constructor() { + qtAction = new QAction(0); + connect(qtAction, SIGNAL(triggered()), SLOT(onTick())); +} + +void pItem::destructor() { + if(action.state.menu) action.state.menu->remove(item); + delete qtAction; +} + +void pItem::onTick() { + if(item.onTick) item.onTick(); +} diff --git a/phoenix/qt/action/menu.cpp b/phoenix/qt/action/menu.cpp new file mode 100755 index 00000000..f484e17e --- /dev/null +++ b/phoenix/qt/action/menu.cpp @@ -0,0 +1,47 @@ +void pMenu::append(Action &action) { + if(dynamic_cast(&action)) { + qtMenu->addMenu(((Menu&)action).p.qtMenu); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((Separator&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((Item&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((CheckItem&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((RadioItem&)action).p.qtAction); + } +} + +void pMenu::remove(Action &action) { + if(dynamic_cast(&action)) { + //QMenu::removeMenu() does not exist + qtMenu->clear(); + for(auto &action : menu.state.action) append(action); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((Separator&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((Item&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((CheckItem&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((CheckItem&)action).p.qtAction); + } +} + +void pMenu::setFont(const string &font) { + qtMenu->setFont(pFont::create(font)); + for(auto &item : menu.state.action) item.p.setFont(font); +} + +void pMenu::setText(const string &text) { + qtMenu->setTitle(QString::fromUtf8(text)); +} + +void pMenu::constructor() { + qtMenu = new QMenu; +} + +void pMenu::destructor() { + if(action.state.menu) action.state.menu->remove(menu); + delete qtMenu; +} diff --git a/phoenix/qt/action/radio-item.cpp b/phoenix/qt/action/radio-item.cpp new file mode 100755 index 00000000..56d90281 --- /dev/null +++ b/phoenix/qt/action/radio-item.cpp @@ -0,0 +1,41 @@ +bool pRadioItem::checked() { + return qtAction->isChecked(); +} + +void pRadioItem::setChecked() { + locked = true; + for(auto &item : radioItem.state.group) { + bool checkState = item.p.qtAction == qtAction; + item.state.checked = checkState; + item.p.qtAction->setChecked(checkState); + } + locked = false; +} + +void pRadioItem::setGroup(const reference_array &group) { +} + +void pRadioItem::setText(const string &text) { + qtAction->setText(QString::fromUtf8(text)); +} + +void pRadioItem::constructor() { + qtAction = new QAction(0); + qtGroup = new QActionGroup(0); + qtAction->setCheckable(true); + qtAction->setActionGroup(qtGroup); + qtAction->setChecked(true); + connect(qtAction, SIGNAL(triggered()), SLOT(onTick())); +} + +void pRadioItem::destructor() { + if(action.state.menu) action.state.menu->remove(radioItem); + delete qtAction; +} + +void pRadioItem::onTick() { + if(radioItem.state.checked == false) { + setChecked(); + if(locked == false && radioItem.onTick) radioItem.onTick(); + } +} diff --git a/phoenix/qt/action/separator.cpp b/phoenix/qt/action/separator.cpp new file mode 100755 index 00000000..95e66b6c --- /dev/null +++ b/phoenix/qt/action/separator.cpp @@ -0,0 +1,9 @@ +void pSeparator::constructor() { + qtAction = new QAction(0); + qtAction->setSeparator(true); +} + +void pSeparator::destructor() { + if(action.state.menu) action.state.menu->remove(separator); + delete qtAction; +} diff --git a/phoenix/qt/font.cpp b/phoenix/qt/font.cpp new file mode 100755 index 00000000..bb3261cd --- /dev/null +++ b/phoenix/qt/font.cpp @@ -0,0 +1,40 @@ +Geometry pFont::geometry(const string &description, const string &text) { + return pFont::geometry(pFont::create(description), text); +} + +QFont pFont::create(const string &description) { + lstring part; + part.split(",", description); + for(auto &item : part) item.trim(" "); + + string family = "Sans"; + unsigned size = 8u; + bool bold = false; + bool italic = false; + + if(part[0] != "") family = part[0]; + if(part.size() >= 2) size = decimal(part[1]); + if(part.size() >= 3) bold = part[2].position("Bold"); + if(part.size() >= 3) italic = part[2].position("Italic"); + + QFont qtFont; + qtFont.setFamily(family); + qtFont.setPointSize(size); + if(bold) qtFont.setBold(true); + if(italic) qtFont.setItalic(true); + return qtFont; +} + +Geometry pFont::geometry(const QFont &qtFont, const string &text) { + QFontMetrics metrics(qtFont); + + lstring lines; + lines.split("\n", text); + + unsigned maxWidth = 0; + for(auto &line : lines) { + maxWidth = max(maxWidth, metrics.width(line)); + } + + return { 0, 0, maxWidth, metrics.height() * lines.size() }; +} diff --git a/phoenix/qt/message-window.cpp b/phoenix/qt/message-window.cpp new file mode 100755 index 00000000..c850547b --- /dev/null +++ b/phoenix/qt/message-window.cpp @@ -0,0 +1,47 @@ +static QMessageBox::StandardButtons MessageWindow_buttons(MessageWindow::Buttons buttons) { + QMessageBox::StandardButtons standardButtons = QMessageBox::NoButton; + if(buttons == MessageWindow::Buttons::Ok) standardButtons = QMessageBox::Ok; + if(buttons == MessageWindow::Buttons::OkCancel) standardButtons = QMessageBox::Ok | QMessageBox::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) standardButtons = QMessageBox::Yes | QMessageBox::No; + return standardButtons; +} + +static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, QMessageBox::StandardButton response) { + if(response == QMessageBox::Ok) return MessageWindow::Response::Ok; + if(response == QMessageBox::Cancel) return MessageWindow::Response::Cancel; + if(response == QMessageBox::Yes) return MessageWindow::Response::Yes; + if(response == QMessageBox::No) return MessageWindow::Response::No; + + //MessageWindow was closed via window manager, rather than by a button; assume a cancel/no response + if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow_response( + buttons, QMessageBox::information(&parent != &Window::None ? parent.p.qtWindow : 0, " ", + QString::fromUtf8(text), MessageWindow_buttons(buttons)) + ); +} + +MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow_response( + buttons, QMessageBox::question(&parent != &Window::None ? parent.p.qtWindow : 0, " ", + QString::fromUtf8(text), MessageWindow_buttons(buttons)) + ); +} + +MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow_response( + buttons, QMessageBox::warning(&parent != &Window::None ? parent.p.qtWindow : 0, " ", + QString::fromUtf8(text), MessageWindow_buttons(buttons)) + ); +} + +MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow_response( + buttons, QMessageBox::critical(&parent != &Window::None ? parent.p.qtWindow : 0, " ", + QString::fromUtf8(text), MessageWindow_buttons(buttons)) + ); +} diff --git a/phoenix/qt/platform.cpp b/phoenix/qt/platform.cpp new file mode 100755 index 00000000..bbcb9981 --- /dev/null +++ b/phoenix/qt/platform.cpp @@ -0,0 +1,143 @@ +#include "platform.moc.hpp" +#include "platform.moc" + +#include "settings.cpp" +#include "font.cpp" +#include "timer.cpp" +#include "message-window.cpp" +#include "window.cpp" + +#include "action/action.cpp" +#include "action/menu.cpp" +#include "action/separator.cpp" +#include "action/item.cpp" +#include "action/check-item.cpp" +#include "action/radio-item.cpp" + +#include "widget/widget.cpp" +#include "widget/button.cpp" +#include "widget/canvas.cpp" +#include "widget/check-box.cpp" +#include "widget/combo-box.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-box.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +Geometry pOS::availableGeometry() { + QRect rect = QApplication::desktop()->availableGeometry(); + return { rect.x(), rect.y(), rect.width(), rect.height() }; +} + +Geometry pOS::desktopGeometry() { + QRect rect = QApplication::desktop()->screenGeometry(); + return { 0, 0, rect.width(), rect.height() }; +} + +string pOS::fileLoad(Window &parent, const string &path, const lstring &filter) { + string filterList; + for(auto &item : filter) { + filterList.append(item); + filterList.append(";;"); + } + filterList.rtrim<1>(";;"); + + //convert filter list from phoenix to Qt format, example: + //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" + signed parenthesis = 0; + for(auto &n : filterList) { + if(n == '(') parenthesis++; + if(n == ')') parenthesis--; + if(n == ',' && parenthesis) n = ' '; + } + + QString filename = QFileDialog::getOpenFileName( + &parent != &Window::None ? parent.p.qtWindow : 0, "Load File", + QString::fromUtf8(path), QString::fromUtf8(filterList) + ); + return filename.toUtf8().constData(); +} + +string pOS::fileSave(Window &parent, const string &path, const lstring &filter) { + string filterList; + for(auto &item : filter) { + filterList.append(item); + filterList.append(";;"); + } + filterList.rtrim<1>(";;"); + + //convert filter list from phoenix to Qt format, example: + //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" + signed parenthesis = 0; + for(auto &n : filterList) { + if(n == '(') parenthesis++; + if(n == ')') parenthesis--; + if(n == ',' && parenthesis) n = ' '; + } + + QString filename = QFileDialog::getSaveFileName( + &parent != &Window::None ? parent.p.qtWindow : 0, "Save File", + QString::fromUtf8(path), QString::fromUtf8(filterList) + ); + return filename.toUtf8().constData(); +} + +string pOS::folderSelect(Window &parent, const string &path) { + QString directory = QFileDialog::getExistingDirectory( + &parent != &Window::None ? parent.p.qtWindow : 0, "Select Directory", + QString::fromUtf8(path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks + ); + string name = directory.toUtf8().constData(); + if(name != "" && name.endswith("/") == false) name.append("/"); + return name; +} + +void pOS::main() { + QApplication::exec(); +} + +bool pOS::pendingEvents() { + return QApplication::hasPendingEvents(); +} + +void pOS::processEvents() { + while(pendingEvents()) QApplication::processEvents(); +} + +void pOS::quit() { + settings->save(); + + QApplication::quit(); + //note: QApplication cannot be deleted; or libQtGui will crash + qtApplication = 0; +} + +void pOS::syncX() { + for(unsigned n = 0; n < 8; n++) { + QApplication::syncX(); + OS::processEvents(); + usleep(2000); + } +} + +void pOS::initialize() { + settings = new Settings; + settings->load(); + + static int argc = 1; + static char *argv[2]; + argv[0] = new char[8]; + argv[1] = 0; + strcpy(argv[0], "phoenix"); + char **argvp = argv; + + qtApplication = new QApplication(argc, argvp); +} diff --git a/phoenix/qt/platform.moc b/phoenix/qt/platform.moc new file mode 100755 index 00000000..7e04fac2 --- /dev/null +++ b/phoenix/qt/platform.moc @@ -0,0 +1,1105 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'platform.moc.hpp' +** +** Created: Wed Nov 2 21:16:00 2011 +** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'platform.moc.hpp' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 62 +#error "This file was generated using the moc from 4.7.0. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_pTimer[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 8, 7, 7, 7, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pTimer[] = { + "pTimer\0\0onTimeout()\0" +}; + +const QMetaObject pTimer::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pTimer, + qt_meta_data_pTimer, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pTimer::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pTimer::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pTimer::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pTimer)) + return static_cast(const_cast< pTimer*>(this)); + if (!strcmp(_clname, "pObject")) + return static_cast< pObject*>(const_cast< pTimer*>(this)); + return QObject::qt_metacast(_clname); +} + +int pTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onTimeout(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pWindow[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_pWindow[] = { + "pWindow\0" +}; + +const QMetaObject pWindow::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pWindow, + qt_meta_data_pWindow, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pWindow::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pWindow::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pWindow::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pWindow)) + return static_cast(const_cast< pWindow*>(this)); + if (!strcmp(_clname, "pObject")) + return static_cast< pObject*>(const_cast< pWindow*>(this)); + return QObject::qt_metacast(_clname); +} + +int pWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} +static const uint qt_meta_data_pItem[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 7, 6, 6, 6, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pItem[] = { + "pItem\0\0onTick()\0" +}; + +const QMetaObject pItem::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pItem, + qt_meta_data_pItem, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pItem)) + return static_cast(const_cast< pItem*>(this)); + if (!strcmp(_clname, "pAction")) + return static_cast< pAction*>(const_cast< pItem*>(this)); + return QObject::qt_metacast(_clname); +} + +int pItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onTick(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pCheckItem[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 12, 11, 11, 11, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pCheckItem[] = { + "pCheckItem\0\0onTick()\0" +}; + +const QMetaObject pCheckItem::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pCheckItem, + qt_meta_data_pCheckItem, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pCheckItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pCheckItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pCheckItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pCheckItem)) + return static_cast(const_cast< pCheckItem*>(this)); + if (!strcmp(_clname, "pAction")) + return static_cast< pAction*>(const_cast< pCheckItem*>(this)); + return QObject::qt_metacast(_clname); +} + +int pCheckItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onTick(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pRadioItem[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 12, 11, 11, 11, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pRadioItem[] = { + "pRadioItem\0\0onTick()\0" +}; + +const QMetaObject pRadioItem::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pRadioItem, + qt_meta_data_pRadioItem, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pRadioItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pRadioItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pRadioItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pRadioItem)) + return static_cast(const_cast< pRadioItem*>(this)); + if (!strcmp(_clname, "pAction")) + return static_cast< pAction*>(const_cast< pRadioItem*>(this)); + return QObject::qt_metacast(_clname); +} + +int pRadioItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onTick(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pButton[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 9, 8, 8, 8, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pButton[] = { + "pButton\0\0onTick()\0" +}; + +const QMetaObject pButton::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pButton, + qt_meta_data_pButton, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pButton::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pButton::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pButton::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pButton)) + return static_cast(const_cast< pButton*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pButton*>(this)); + return QObject::qt_metacast(_clname); +} + +int pButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onTick(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pCanvas[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_pCanvas[] = { + "pCanvas\0" +}; + +const QMetaObject pCanvas::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pCanvas, + qt_meta_data_pCanvas, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pCanvas::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pCanvas::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pCanvas::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pCanvas)) + return static_cast(const_cast< pCanvas*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pCanvas*>(this)); + return QObject::qt_metacast(_clname); +} + +int pCanvas::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} +static const uint qt_meta_data_pCheckBox[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pCheckBox[] = { + "pCheckBox\0\0onTick()\0" +}; + +const QMetaObject pCheckBox::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pCheckBox, + qt_meta_data_pCheckBox, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pCheckBox::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pCheckBox::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pCheckBox::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pCheckBox)) + return static_cast(const_cast< pCheckBox*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pCheckBox*>(this)); + return QObject::qt_metacast(_clname); +} + +int pCheckBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onTick(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pComboBox[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pComboBox[] = { + "pComboBox\0\0onChange()\0" +}; + +const QMetaObject pComboBox::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pComboBox, + qt_meta_data_pComboBox, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pComboBox::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pComboBox::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pComboBox::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pComboBox)) + return static_cast(const_cast< pComboBox*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pComboBox*>(this)); + return QObject::qt_metacast(_clname); +} + +int pComboBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pHexEdit[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 10, 9, 9, 9, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pHexEdit[] = { + "pHexEdit\0\0onScroll()\0" +}; + +const QMetaObject pHexEdit::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pHexEdit, + qt_meta_data_pHexEdit, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pHexEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pHexEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pHexEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pHexEdit)) + return static_cast(const_cast< pHexEdit*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pHexEdit*>(this)); + return QObject::qt_metacast(_clname); +} + +int pHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onScroll(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pHorizontalScrollBar[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 22, 21, 21, 21, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pHorizontalScrollBar[] = { + "pHorizontalScrollBar\0\0onChange()\0" +}; + +const QMetaObject pHorizontalScrollBar::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pHorizontalScrollBar, + qt_meta_data_pHorizontalScrollBar, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pHorizontalScrollBar::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pHorizontalScrollBar::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pHorizontalScrollBar::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pHorizontalScrollBar)) + return static_cast(const_cast< pHorizontalScrollBar*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pHorizontalScrollBar*>(this)); + return QObject::qt_metacast(_clname); +} + +int pHorizontalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pHorizontalSlider[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 19, 18, 18, 18, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pHorizontalSlider[] = { + "pHorizontalSlider\0\0onChange()\0" +}; + +const QMetaObject pHorizontalSlider::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pHorizontalSlider, + qt_meta_data_pHorizontalSlider, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pHorizontalSlider::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pHorizontalSlider::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pHorizontalSlider::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pHorizontalSlider)) + return static_cast(const_cast< pHorizontalSlider*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pHorizontalSlider*>(this)); + return QObject::qt_metacast(_clname); +} + +int pHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pLineEdit[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 2, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + 24, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pLineEdit[] = { + "pLineEdit\0\0onActivate()\0onChange()\0" +}; + +const QMetaObject pLineEdit::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pLineEdit, + qt_meta_data_pLineEdit, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pLineEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pLineEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pLineEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pLineEdit)) + return static_cast(const_cast< pLineEdit*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pLineEdit*>(this)); + return QObject::qt_metacast(_clname); +} + +int pLineEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onActivate(); break; + case 1: onChange(); break; + default: ; + } + _id -= 2; + } + return _id; +} +static const uint qt_meta_data_pListView[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 3, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + 29, 24, 10, 10, 0x0a, + 56, 24, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pListView[] = { + "pListView\0\0onActivate()\0item\0" + "onChange(QTreeWidgetItem*)\0" + "onTick(QTreeWidgetItem*)\0" +}; + +const QMetaObject pListView::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pListView, + qt_meta_data_pListView, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pListView::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pListView::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pListView::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pListView)) + return static_cast(const_cast< pListView*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pListView*>(this)); + return QObject::qt_metacast(_clname); +} + +int pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onActivate(); break; + case 1: onChange((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break; + case 2: onTick((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break; + default: ; + } + _id -= 3; + } + return _id; +} +static const uint qt_meta_data_pRadioBox[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pRadioBox[] = { + "pRadioBox\0\0onTick()\0" +}; + +const QMetaObject pRadioBox::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pRadioBox, + qt_meta_data_pRadioBox, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pRadioBox::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pRadioBox::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pRadioBox::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pRadioBox)) + return static_cast(const_cast< pRadioBox*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pRadioBox*>(this)); + return QObject::qt_metacast(_clname); +} + +int pRadioBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onTick(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pTextEdit[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 11, 10, 10, 10, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pTextEdit[] = { + "pTextEdit\0\0onChange()\0" +}; + +const QMetaObject pTextEdit::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pTextEdit, + qt_meta_data_pTextEdit, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pTextEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pTextEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pTextEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pTextEdit)) + return static_cast(const_cast< pTextEdit*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pTextEdit*>(this)); + return QObject::qt_metacast(_clname); +} + +int pTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pVerticalScrollBar[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 20, 19, 19, 19, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pVerticalScrollBar[] = { + "pVerticalScrollBar\0\0onChange()\0" +}; + +const QMetaObject pVerticalScrollBar::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pVerticalScrollBar, + qt_meta_data_pVerticalScrollBar, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pVerticalScrollBar::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pVerticalScrollBar::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pVerticalScrollBar::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pVerticalScrollBar)) + return static_cast(const_cast< pVerticalScrollBar*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pVerticalScrollBar*>(this)); + return QObject::qt_metacast(_clname); +} + +int pVerticalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_pVerticalSlider[] = { + + // content: + 5, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 17, 16, 16, 16, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_pVerticalSlider[] = { + "pVerticalSlider\0\0onChange()\0" +}; + +const QMetaObject pVerticalSlider::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_pVerticalSlider, + qt_meta_data_pVerticalSlider, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &pVerticalSlider::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *pVerticalSlider::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *pVerticalSlider::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_pVerticalSlider)) + return static_cast(const_cast< pVerticalSlider*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pVerticalSlider*>(this)); + return QObject::qt_metacast(_clname); +} + +int pVerticalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: onChange(); break; + default: ; + } + _id -= 1; + } + return _id; +} +QT_END_MOC_NAMESPACE diff --git a/phoenix/qt/platform.moc.hpp b/phoenix/qt/platform.moc.hpp new file mode 100755 index 00000000..133ad9c3 --- /dev/null +++ b/phoenix/qt/platform.moc.hpp @@ -0,0 +1,587 @@ +static QApplication *qtApplication = 0; + +struct Settings : public configuration { + unsigned frameGeometryX; + unsigned frameGeometryY; + unsigned frameGeometryWidth; + unsigned frameGeometryHeight; + unsigned menuGeometryHeight; + unsigned statusGeometryHeight; + + void load(); + void save(); + Settings(); +}; + +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static QFont create(const string &description); + static Geometry geometry(const QFont &qtFont, const string &text); +}; + +struct pObject { + Object &object; + bool locked; + + pObject(Object &object) : object(object), locked(false) {} + virtual ~pObject() {} + void constructor() {} + void destructor() {} +}; + +struct pOS : public pObject { + static Geometry availableGeometry(); + static Geometry desktopGeometry(); + static string fileLoad(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + static void syncX(); + + static void initialize(); +}; + +struct pTimer : public QObject, public pObject { + Q_OBJECT + +public: + Timer &timer; + QTimer *qtTimer; + + void setEnabled(bool enabled); + void setInterval(unsigned milliseconds); + + pTimer(Timer &timer) : pObject(timer), timer(timer) {} + void constructor(); + void destructor(); + +public slots: + void onTimeout(); +}; + +struct pMessageWindow : public pObject { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + +struct pWindow : public QObject, public pObject { + Q_OBJECT + +public: + Window &window; + struct QtWindow : public QWidget { + pWindow &self; + void closeEvent(QCloseEvent*); + void moveEvent(QMoveEvent*); + void resizeEvent(QResizeEvent*); + QSize sizeHint() const; + QtWindow(pWindow &self) : self(self) {} + } *qtWindow; + QVBoxLayout *qtLayout; + QMenuBar *qtMenu; + QStatusBar *qtStatus; + QWidget *qtContainer; + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + Geometry frameMargin(); + bool focused(); + Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFocused(); + void setFullScreen(bool fullScreen); + void setGeometry(const Geometry &geometry); + void setMenuFont(const string &font); + void setMenuVisible(bool visible); + void setResizable(bool resizable); + void setStatusFont(const string &font); + void setStatusText(const string &text); + void setStatusVisible(bool visible); + void setTitle(const string &text); + void setVisible(bool visible); + void setWidgetFont(const string &font); + + pWindow(Window &window) : pObject(window), window(window) {} + void constructor(); + void destructor(); + void updateFrameGeometry(); +}; + +struct pAction : public pObject { + Action &action; + + void setEnabled(bool enabled); + void setFont(const string &font); + void setVisible(bool visible); + + pAction(Action &action) : pObject(action), action(action) {} + void constructor(); + void destructor(); +}; + +struct pMenu : public pAction { + Menu &menu; + QMenu *qtMenu; + + void append(Action &action); + void remove(Action &action); + void setFont(const string &font); + void setText(const string &text); + + pMenu(Menu &menu) : pAction(menu), menu(menu) {} + void constructor(); + void destructor(); +}; + +struct pSeparator : public pAction { + Separator &separator; + QAction *qtAction; + + pSeparator(Separator &separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); +}; + +struct pItem : public QObject, public pAction { + Q_OBJECT + +public: + Item &item; + QAction *qtAction; + + void setText(const string &text); + + pItem(Item &item) : pAction(item), item(item) {} + void constructor(); + void destructor(); + +public slots: + void onTick(); +}; + +struct pCheckItem : public QObject, public pAction { + Q_OBJECT + +public: + CheckItem &checkItem; + QAction *qtAction; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} + void constructor(); + void destructor(); + +public slots: + void onTick(); +}; + +struct pRadioItem : public QObject, public pAction { + Q_OBJECT + +public: + RadioItem &radioItem; + QAction *qtAction; + QActionGroup *qtGroup; + + bool checked(); + void setChecked(); + void setGroup(const reference_array &group); + void setText(const string &text); + + pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} + void constructor(); + void destructor(); + +public slots: + void onTick(); +}; + +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} + + void constructor() {} + void destructor() {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} + + void constructor() {} + void destructor() {} +}; + +struct pWidget : public pSizable { + Widget &widget; + QWidget *qtWidget; + + virtual Geometry minimumGeometry(); + void setEnabled(bool enabled); + void setFocused(); + void setFont(const string &font); + virtual void setGeometry(const Geometry &geometry); + void setVisible(bool visible); + + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} + void constructor(); + void synchronizeState(); + void destructor(); + virtual void orphan(); +}; + +struct pButton : public QObject, public pWidget { + Q_OBJECT + +public: + Button &button; + QPushButton *qtButton; + + Geometry minimumGeometry(); + void setText(const string &text); + + pButton(Button &button) : pWidget(button), button(button) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onTick(); +}; + +struct pCanvas : public QObject, public pWidget { + Q_OBJECT + +public: + Canvas &canvas; + QImage *qtImage; + struct QtCanvas : public QWidget { + pCanvas &self; + void paintEvent(QPaintEvent*); + QtCanvas(pCanvas &self); + } *qtCanvas; + + void setSize(const Size &size); + void update(); + + pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: +}; + +struct pCheckBox : public QObject, public pWidget { + Q_OBJECT + +public: + CheckBox &checkBox; + QCheckBox *qtCheckBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onTick(); +}; + +struct pComboBox : public QObject, public pWidget { + Q_OBJECT + +public: + ComboBox &comboBox; + QComboBox *qtComboBox; + + void append(const string &text); + Geometry minimumGeometry(); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pHexEdit : public QObject, public pWidget { + Q_OBJECT + +public: + HexEdit &hexEdit; + struct QtHexEdit : public QTextEdit { + pHexEdit &self; + void keyPressEvent(QKeyEvent*); + void keyPressEventAcknowledge(QKeyEvent*); + QtHexEdit(pHexEdit &self) : self(self) {} + } *qtHexEdit; + QHBoxLayout *qtLayout; + QScrollBar *qtScroll; + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} + void constructor(); + void destructor(); + void orphan(); + void keyPressEvent(QKeyEvent*); + +public slots: + void onScroll(); +}; + +struct pHorizontalScrollBar : public QObject, public pWidget { + Q_OBJECT + +public: + HorizontalScrollBar &horizontalScrollBar; + QScrollBar *qtScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pHorizontalSlider : public QObject, public pWidget { + Q_OBJECT + +public: + HorizontalSlider &horizontalSlider; + QSlider *qtSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pLabel : public pWidget { + Label &label; + QLabel *qtLabel; + + Geometry minimumGeometry(); + void setText(const string &text); + + pLabel(Label &label) : pWidget(label), label(label) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLineEdit : public QObject, public pWidget { + Q_OBJECT + +public: + LineEdit &lineEdit; + QLineEdit *qtLineEdit; + + Geometry minimumGeometry(); + void setEditable(bool editable); + void setText(const string &text); + string text(); + + pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onActivate(); + void onChange(); +}; + +struct pListView : public QObject, public pWidget { + Q_OBJECT + +public: + ListView &listView; + QTreeWidget *qtListView; + + void append(const lstring &text); + void autoSizeColumns(); + bool checked(unsigned row); + void modify(unsigned row, const lstring &text); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable); + void setChecked(unsigned row, bool checked); + void setHeaderText(const lstring &text); + void setHeaderVisible(bool visible); + void setSelected(bool selected); + void setSelection(unsigned row); + + pListView(ListView &listView) : pWidget(listView), listView(listView) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onActivate(); + void onChange(QTreeWidgetItem *item); + void onTick(QTreeWidgetItem *item); +}; + +struct pProgressBar : public pWidget { + ProgressBar &progressBar; + QProgressBar *qtProgressBar; + + Geometry minimumGeometry(); + void setPosition(unsigned position); + + pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pRadioBox : public QObject, public pWidget { + Q_OBJECT + +public: + RadioBox &radioBox; + QRadioButton *qtRadioBox; + QButtonGroup *qtGroup; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(); + void setGroup(const reference_array &group); + void setText(const string &text); + + pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onTick(); +}; + +struct pTextEdit : public QObject, public pWidget { + Q_OBJECT + +public: + TextEdit &textEdit; + QTextEdit *qtTextEdit; + + void setCursorPosition(unsigned position); + void setEditable(bool editable); + void setText(const string &text); + void setWordWrap(bool wordWrap); + string text(); + + pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pVerticalScrollBar : public QObject, public pWidget { + Q_OBJECT + +public: + VerticalScrollBar &verticalScrollBar; + QScrollBar *qtScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pVerticalSlider : public QObject, public pWidget { + Q_OBJECT + +public: + VerticalSlider &verticalSlider; + QSlider *qtSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onChange(); +}; + +struct pViewport : public pWidget { + Viewport &viewport; + + uintptr_t handle(); + + pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); + void destructor(); + void orphan(); +}; diff --git a/phoenix/qt/settings.cpp b/phoenix/qt/settings.cpp new file mode 100755 index 00000000..4a849014 --- /dev/null +++ b/phoenix/qt/settings.cpp @@ -0,0 +1,24 @@ +static Settings *settings = nullptr; + +void Settings::load() { + string path = { userpath(), ".config/phoenix/qt.cfg" }; + configuration::load(path); +} + +void Settings::save() { + string path = { userpath(), ".config/" }; + mkdir(path, 0755); + path.append("phoenix/"); + mkdir(path, 0755); + path.append("qt.cfg"); + configuration::save(path); +} + +Settings::Settings() { + attach(frameGeometryX = 4, "frameGeometryX"); + attach(frameGeometryY = 24, "frameGeometryY"); + attach(frameGeometryWidth = 8, "frameGeometryWidth"); + attach(frameGeometryHeight = 28, "frameGeometryHeight"); + attach(menuGeometryHeight = 20, "menuGeometryHeight"); + attach(statusGeometryHeight = 20, "statusGeometryHeight"); +} diff --git a/phoenix/qt/timer.cpp b/phoenix/qt/timer.cpp new file mode 100755 index 00000000..61f00ba8 --- /dev/null +++ b/phoenix/qt/timer.cpp @@ -0,0 +1,25 @@ +void pTimer::setEnabled(bool enabled) { + if(enabled) { + qtTimer->start(); + } else { + qtTimer->stop(); + } +} + +void pTimer::setInterval(unsigned milliseconds) { + qtTimer->setInterval(milliseconds); +} + +void pTimer::constructor() { + qtTimer = new QTimer; + qtTimer->setInterval(0); + connect(qtTimer, SIGNAL(timeout()), SLOT(onTimeout())); +} + +void pTimer::destructor() { + delete qtTimer; +} + +void pTimer::onTimeout() { + if(timer.onTimeout) timer.onTimeout(); +} diff --git a/phoenix/qt/widget/button.cpp b/phoenix/qt/widget/button.cpp new file mode 100755 index 00000000..9f5d5a6a --- /dev/null +++ b/phoenix/qt/widget/button.cpp @@ -0,0 +1,30 @@ +Geometry pButton::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), button.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 12 }; +} + +void pButton::setText(const string &text) { + qtButton->setText(QString::fromUtf8(text)); +} + +void pButton::constructor() { + qtWidget = qtButton = new QPushButton; + connect(qtButton, SIGNAL(released()), SLOT(onTick())); + + pWidget::synchronizeState(); + setText(button.state.text); +} + +void pButton::destructor() { + delete qtButton; + qtWidget = qtButton = 0; +} + +void pButton::orphan() { + destructor(); + constructor(); +} + +void pButton::onTick() { + if(button.onTick) button.onTick(); +} diff --git a/phoenix/qt/widget/canvas.cpp b/phoenix/qt/widget/canvas.cpp new file mode 100755 index 00000000..4adc54e5 --- /dev/null +++ b/phoenix/qt/widget/canvas.cpp @@ -0,0 +1,45 @@ +void pCanvas::setSize(const Size &size) { + delete qtImage; + qtImage = new QImage(size.width, size.height, QImage::Format_RGB32); +} + +void pCanvas::update() { + memcpy(qtImage->bits(), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + qtCanvas->update(); +} + +void pCanvas::constructor() { + qtWidget = qtCanvas = new QtCanvas(*this); + qtImage = new QImage(canvas.state.width, canvas.state.height, QImage::Format_RGB32); + memcpy(qtImage->bits(), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + + pWidget::synchronizeState(); + update(); +} + +void pCanvas::destructor() { + delete qtCanvas; + delete qtImage; + qtWidget = qtCanvas = 0; + qtImage = 0; +} + +void pCanvas::orphan() { + destructor(); + constructor(); +} + +void pCanvas::QtCanvas::paintEvent(QPaintEvent *event) { + QPainter painter(self.qtCanvas); + painter.drawImage(0, 0, *self.qtImage); + +//this will scale the source image to fit the target widget size (nearest-neighbor): +//painter.drawImage( +// QRect(0, 0, geometry().width(), geometry().height()), +// *self.qtImage, +// QRect(0, 0, self.canvas.state.width, self.canvas.state.height) +//); +} + +pCanvas::QtCanvas::QtCanvas(pCanvas &self) : self(self) { +} diff --git a/phoenix/qt/widget/check-box.cpp b/phoenix/qt/widget/check-box.cpp new file mode 100755 index 00000000..b62e4384 --- /dev/null +++ b/phoenix/qt/widget/check-box.cpp @@ -0,0 +1,42 @@ +bool pCheckBox::checked() { + return qtCheckBox->isChecked(); +} + +Geometry pCheckBox::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), checkBox.state.text); + return { 0, 0, geometry.width + 26, geometry.height + 6 }; +} + +void pCheckBox::setChecked(bool checked) { + locked = true; + qtCheckBox->setChecked(checked); + locked = false; +} + +void pCheckBox::setText(const string &text) { + qtCheckBox->setText(QString::fromUtf8(text)); +} + +void pCheckBox::constructor() { + qtWidget = qtCheckBox = new QCheckBox; + connect(qtCheckBox, SIGNAL(stateChanged(int)), SLOT(onTick())); + + pWidget::synchronizeState(); + setChecked(checkBox.state.checked); + setText(checkBox.state.text); +} + +void pCheckBox::destructor() { + delete qtCheckBox; + qtWidget = qtCheckBox = 0; +} + +void pCheckBox::orphan() { + destructor(); + constructor(); +} + +void pCheckBox::onTick() { + checkBox.state.checked = checked(); + if(locked == false && checkBox.onTick) checkBox.onTick(); +} diff --git a/phoenix/qt/widget/combo-box.cpp b/phoenix/qt/widget/combo-box.cpp new file mode 100755 index 00000000..f614b189 --- /dev/null +++ b/phoenix/qt/widget/combo-box.cpp @@ -0,0 +1,56 @@ +void pComboBox::append(const string &text) { + locked = true; + qtComboBox->addItem(QString::fromUtf8(text)); + locked = false; +} + +Geometry pComboBox::minimumGeometry() { + unsigned maximumWidth = 0; + for(auto &text : comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(qtWidget->font(), text).width); + Geometry geometry = pFont::geometry(qtWidget->font(), " "); + return { 0, 0, maximumWidth + 32, geometry.height + 12 }; +} + +void pComboBox::reset() { + locked = true; + while(qtComboBox->count()) qtComboBox->removeItem(0); + locked = false; +} + +unsigned pComboBox::selection() { + signed index = qtComboBox->currentIndex(); + return index >= 0 ? index : 0; +} + +void pComboBox::setSelection(unsigned row) { + locked = true; + qtComboBox->setCurrentIndex(row); + locked = false; +} + +void pComboBox::constructor() { + qtWidget = qtComboBox = new QComboBox; + connect(qtComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + unsigned selection = comboBox.state.selection; + locked = true; + for(auto &text : comboBox.state.text) append(text); + locked = false; + setSelection(selection); +} + +void pComboBox::destructor() { + delete qtComboBox; + qtWidget = qtComboBox = 0; +} + +void pComboBox::orphan() { + destructor(); + constructor(); +} + +void pComboBox::onChange() { + comboBox.state.selection = selection(); + if(locked == false && comboBox.onChange) comboBox.onChange(); +} diff --git a/phoenix/qt/widget/hex-edit.cpp b/phoenix/qt/widget/hex-edit.cpp new file mode 100755 index 00000000..fdeebe4a --- /dev/null +++ b/phoenix/qt/widget/hex-edit.cpp @@ -0,0 +1,191 @@ +void pHexEdit::setColumns(unsigned columns) { + update(); +} + +void pHexEdit::setLength(unsigned length) { + //add one if last row is not equal to column length (eg only part of the row is present) + bool indivisible = hexEdit.state.columns == 0 || (hexEdit.state.length % hexEdit.state.columns) != 0; + qtScroll->setRange(0, hexEdit.state.length / hexEdit.state.columns + indivisible - hexEdit.state.rows); + update(); +} + +void pHexEdit::setOffset(unsigned offset) { + locked = true; + qtScroll->setSliderPosition(hexEdit.state.offset / hexEdit.state.columns); + locked = false; + update(); +} + +void pHexEdit::setRows(unsigned rows) { + qtScroll->setPageStep(hexEdit.state.rows); + update(); +} + +void pHexEdit::update() { + if(!hexEdit.onRead) { + qtHexEdit->setPlainText(""); + return; + } + + unsigned cursorPosition = qtHexEdit->textCursor().position(); + + string output; + unsigned offset = hexEdit.state.offset; + for(unsigned row = 0; row < hexEdit.state.rows; row++) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + + for(unsigned column = 0; column < hexEdit.state.columns; column++) { + if(offset < hexEdit.state.length) { + uint8_t data = hexEdit.onRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 }; + ansidata.append(buffer); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= hexEdit.state.length) break; + if(row != hexEdit.state.rows - 1) output.append("\n"); + } + + qtHexEdit->setPlainText(QString::fromUtf8(output)); + QTextCursor cursor = qtHexEdit->textCursor(); + cursor.setPosition(cursorPosition); + qtHexEdit->setTextCursor(cursor); +} + +void pHexEdit::constructor() { + qtWidget = qtHexEdit = new QtHexEdit(*this); + + qtHexEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + qtHexEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + qtLayout = new QHBoxLayout; + qtLayout->setAlignment(Qt::AlignRight); + qtLayout->setMargin(0); + qtLayout->setSpacing(0); + qtHexEdit->setLayout(qtLayout); + + qtScroll = new QScrollBar(Qt::Vertical); + qtScroll->setSingleStep(1); + qtLayout->addWidget(qtScroll); + + connect(qtScroll, SIGNAL(actionTriggered(int)), SLOT(onScroll())); + + pWidget::synchronizeState(); + setColumns(hexEdit.state.columns); + setRows(hexEdit.state.rows); + setLength(hexEdit.state.length); + setOffset(hexEdit.state.offset); + update(); +} + +void pHexEdit::destructor() { + delete qtScroll; + delete qtLayout; + delete qtHexEdit; + qtWidget = qtHexEdit = 0; + qtLayout = 0; + qtScroll = 0; +} + +void pHexEdit::orphan() { + destructor(); + constructor(); +} + +void pHexEdit::keyPressEvent(QKeyEvent *event) { + if(!hexEdit.onRead) return; + + QTextCursor cursor = qtHexEdit->textCursor(); + unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1; + unsigned cursorY = cursor.position() / lineWidth; + unsigned cursorX = cursor.position() % lineWidth; + + unsigned nibble; + switch(event->key()) { + case Qt::Key_0: nibble = 0; break; + case Qt::Key_1: nibble = 1; break; + case Qt::Key_2: nibble = 2; break; + case Qt::Key_3: nibble = 3; break; + case Qt::Key_4: nibble = 4; break; + case Qt::Key_5: nibble = 5; break; + case Qt::Key_6: nibble = 6; break; + case Qt::Key_7: nibble = 7; break; + case Qt::Key_8: nibble = 8; break; + case Qt::Key_9: nibble = 9; break; + case Qt::Key_A: nibble = 10; break; + case Qt::Key_B: nibble = 11; break; + case Qt::Key_C: nibble = 12; break; + case Qt::Key_D: nibble = 13; break; + case Qt::Key_E: nibble = 14; break; + case Qt::Key_F: nibble = 15; break; + default: { + //allow navigation keys to move cursor, but block text input + qtHexEdit->setTextInteractionFlags(Qt::TextInteractionFlags( + Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse + )); + qtHexEdit->keyPressEventAcknowledge(event); + qtHexEdit->setTextInteractionFlags(Qt::TextEditorInteraction); + return; + } + } + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < hexEdit.state.columns) { + //not in ANSI region + unsigned offset = hexEdit.state.offset + (cursorY * hexEdit.state.columns + cursorX); + + if(offset >= hexEdit.state.length) return; //do not edit past end of file + uint8_t data = hexEdit.onRead(offset); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (nibble << 0); + } else { + data = (data & 0x0f) | (nibble << 4); + } + if(hexEdit.onWrite) hexEdit.onWrite(offset, data); + + //auto-advance cursor to next nibble/byte + unsigned step = 1; + if(cursorNibble && cursorX != hexEdit.state.columns - 1) step = 2; + cursor.setPosition(cursor.position() + step); + qtHexEdit->setTextCursor(cursor); + + //refresh output to reflect modified data + update(); + } + } + } +} + +void pHexEdit::onScroll() { + if(locked) return; + unsigned offset = qtScroll->sliderPosition(); + hexEdit.state.offset = offset * hexEdit.state.columns; + update(); +} + +void pHexEdit::QtHexEdit::keyPressEvent(QKeyEvent *event) { + self.keyPressEvent(event); +} + +void pHexEdit::QtHexEdit::keyPressEventAcknowledge(QKeyEvent *event) { + QTextEdit::keyPressEvent(event); +} diff --git a/phoenix/qt/widget/horizontal-scroll-bar.cpp b/phoenix/qt/widget/horizontal-scroll-bar.cpp new file mode 100755 index 00000000..6127c301 --- /dev/null +++ b/phoenix/qt/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,43 @@ +Geometry pHorizontalScrollBar::minimumGeometry() { + return { 0, 0, 0, 15 }; +} + +unsigned pHorizontalScrollBar::position() { + return qtScrollBar->value(); +} + +void pHorizontalScrollBar::setLength(unsigned length) { + length += length == 0; + qtScrollBar->setRange(0, length - 1); + qtScrollBar->setPageStep(length >> 3); +} + +void pHorizontalScrollBar::setPosition(unsigned position) { + qtScrollBar->setValue(position); +} + +void pHorizontalScrollBar::constructor() { + qtWidget = qtScrollBar = new QScrollBar(Qt::Horizontal); + qtScrollBar->setRange(0, 100); + qtScrollBar->setPageStep(101 >> 3); + connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + setLength(horizontalScrollBar.state.length); + setPosition(horizontalScrollBar.state.position); +} + +void pHorizontalScrollBar::destructor() { + delete qtScrollBar; + qtWidget = qtScrollBar = 0; +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); +} + +void pHorizontalScrollBar::onChange() { + horizontalScrollBar.state.position = position(); + if(horizontalScrollBar.onChange) horizontalScrollBar.onChange(); +} diff --git a/phoenix/qt/widget/horizontal-slider.cpp b/phoenix/qt/widget/horizontal-slider.cpp new file mode 100755 index 00000000..5401aae1 --- /dev/null +++ b/phoenix/qt/widget/horizontal-slider.cpp @@ -0,0 +1,43 @@ +Geometry pHorizontalSlider::minimumGeometry() { + return { 0, 0, 0, 20 }; +} + +unsigned pHorizontalSlider::position() { + return qtSlider->value(); +} + +void pHorizontalSlider::setLength(unsigned length) { + length += length == 0; + qtSlider->setRange(0, length - 1); + qtSlider->setPageStep(length >> 3); +} + +void pHorizontalSlider::setPosition(unsigned position) { + qtSlider->setValue(position); +} + +void pHorizontalSlider::constructor() { + qtWidget = qtSlider = new QSlider(Qt::Horizontal); + qtSlider->setRange(0, 100); + qtSlider->setPageStep(101 >> 3); + connect(qtSlider, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + setLength(horizontalSlider.state.length); + setPosition(horizontalSlider.state.position); +} + +void pHorizontalSlider::destructor() { + delete qtSlider; + qtWidget = qtSlider = 0; +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); +} + +void pHorizontalSlider::onChange() { + horizontalSlider.state.position = position(); + if(horizontalSlider.onChange) horizontalSlider.onChange(); +} diff --git a/phoenix/qt/widget/label.cpp b/phoenix/qt/widget/label.cpp new file mode 100755 index 00000000..8dd86eb6 --- /dev/null +++ b/phoenix/qt/widget/label.cpp @@ -0,0 +1,25 @@ +Geometry pLabel::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), label.state.text); + return { 0, 0, geometry.width, geometry.height }; +} + +void pLabel::setText(const string &text) { + qtLabel->setText(QString::fromUtf8(text)); +} + +void pLabel::constructor() { + qtWidget = qtLabel = new QLabel; + + pWidget::synchronizeState(); + setText(label.state.text); +} + +void pLabel::destructor() { + delete qtLabel; + qtWidget = qtLabel = 0; +} + +void pLabel::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/qt/widget/line-edit.cpp b/phoenix/qt/widget/line-edit.cpp new file mode 100755 index 00000000..a13f3b81 --- /dev/null +++ b/phoenix/qt/widget/line-edit.cpp @@ -0,0 +1,45 @@ +Geometry pLineEdit::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), lineEdit.state.text); + return { 0, 0, geometry.width + 12, geometry.height + 12 }; +} + +void pLineEdit::setEditable(bool editable) { + qtLineEdit->setReadOnly(!editable); +} + +void pLineEdit::setText(const string &text) { + qtLineEdit->setText(QString::fromUtf8(text)); +} + +string pLineEdit::text() { + return qtLineEdit->text().toUtf8().constData(); +} + +void pLineEdit::constructor() { + qtWidget = qtLineEdit = new QLineEdit; + connect(qtLineEdit, SIGNAL(returnPressed()), SLOT(onActivate())); + connect(qtLineEdit, SIGNAL(textEdited(const QString&)), SLOT(onChange())); + + pWidget::synchronizeState(); + setEditable(lineEdit.state.editable); + setText(lineEdit.state.text); +} + +void pLineEdit::destructor() { + delete qtLineEdit; + qtWidget = qtLineEdit = 0; +} + +void pLineEdit::orphan() { + destructor(); + constructor(); +} + +void pLineEdit::onActivate() { + if(lineEdit.onActivate) lineEdit.onActivate(); +} + +void pLineEdit::onChange() { + lineEdit.state.text = text(); + if(lineEdit.onChange) lineEdit.onChange(); +} diff --git a/phoenix/qt/widget/list-view.cpp b/phoenix/qt/widget/list-view.cpp new file mode 100755 index 00000000..b366afbe --- /dev/null +++ b/phoenix/qt/widget/list-view.cpp @@ -0,0 +1,147 @@ +void pListView::append(const lstring &text) { + locked = true; + auto items = qtListView->findItems("", Qt::MatchContains); + QTreeWidgetItem *item = new QTreeWidgetItem(qtListView); + item->setData(0, Qt::UserRole, (unsigned)items.size()); + if(listView.state.checkable) item->setCheckState(0, Qt::Unchecked); + for(unsigned n = 0; n < text.size(); n++) { + item->setText(n, QString::fromUtf8(text[n])); + } + locked = false; +} + +void pListView::autoSizeColumns() { + for(unsigned n = 0; n < listView.state.headerText.size(); n++) qtListView->resizeColumnToContents(n); +} + +bool pListView::checked(unsigned row) { + QTreeWidgetItem *item = qtListView->topLevelItem(row); + return item ? item->checkState(0) == Qt::Checked : false; +} + +void pListView::modify(unsigned row, const lstring &text) { + locked = true; + QTreeWidgetItem *item = qtListView->topLevelItem(row); + if(!item) return; + for(unsigned n = 0; n < text.size(); n++) { + item->setText(n, QString::fromUtf8(text[n])); + } + locked = false; +} + +void pListView::reset() { + qtListView->clear(); +} + +bool pListView::selected() { + QTreeWidgetItem *item = qtListView->currentItem(); + return (item && item->isSelected() == true); +} + +unsigned pListView::selection() { + QTreeWidgetItem *item = qtListView->currentItem(); + if(item == 0) return 0; + return item->data(0, Qt::UserRole).toUInt(); +} + +void pListView::setCheckable(bool checkable) { + if(checkable) { + auto items = qtListView->findItems("", Qt::MatchContains); + for(unsigned n = 0; n < items.size(); n++) items[n]->setCheckState(0, Qt::Unchecked); + } +} + +void pListView::setChecked(unsigned row, bool checked) { + locked = true; + QTreeWidgetItem *item = qtListView->topLevelItem(row); + if(item) item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked); + locked = false; +} + +void pListView::setHeaderText(const lstring &text) { + QStringList labels; + for(auto &column : text) labels << QString::fromUtf8(column); + + qtListView->setColumnCount(text.size()); + qtListView->setAlternatingRowColors(text.size() >= 2); + qtListView->setHeaderLabels(labels); + autoSizeColumns(); +} + +void pListView::setHeaderVisible(bool visible) { + qtListView->setHeaderHidden(!visible); + autoSizeColumns(); +} + +void pListView::setSelected(bool selected) { + QTreeWidgetItem *item = qtListView->currentItem(); + if(item) item->setSelected(selected); +} + +void pListView::setSelection(unsigned row) { + locked = true; + QTreeWidgetItem *item = qtListView->currentItem(); + if(item) item->setSelected(false); + qtListView->setCurrentItem(0); + auto items = qtListView->findItems("", Qt::MatchContains); + for(unsigned n = 0; n < items.size(); n++) { + if(items[n]->data(0, Qt::UserRole).toUInt() == row) { + qtListView->setCurrentItem(items[n]); + break; + } + } + locked = false; +} + +void pListView::constructor() { + qtWidget = qtListView = new QTreeWidget; + qtListView->setAllColumnsShowFocus(true); + qtListView->setRootIsDecorated(false); + + connect(qtListView, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate())); + connect(qtListView, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(onChange(QTreeWidgetItem*))); + connect(qtListView, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onTick(QTreeWidgetItem*))); + + pWidget::synchronizeState(); + setCheckable(listView.state.checkable); + setHeaderText(listView.state.headerText.size() ? listView.state.headerText : lstring{ " " }); + setHeaderVisible(listView.state.headerVisible); + for(auto &row : listView.state.text) append(row); + if(listView.state.checkable) { + for(unsigned n = 0; n < listView.state.checked.size(); n++) { + setChecked(n, listView.state.checked[n]); + } + } + setSelected(listView.state.selected); + if(listView.state.selected) setSelection(listView.state.selection); + autoSizeColumns(); +} + +void pListView::destructor() { + delete qtListView; + qtWidget = qtListView = 0; +} + +void pListView::orphan() { + destructor(); + constructor(); +} + +void pListView::onActivate() { + if(locked == false && listView.onActivate) listView.onActivate(); +} + +void pListView::onChange(QTreeWidgetItem *item) { + //Qt bug workaround: clicking items with mouse does not mark items as selected + if(item) item->setSelected(true); + listView.state.selected = selected(); + if(listView.state.selected) listView.state.selection = selection(); + if(locked == false && listView.onChange) listView.onChange(); +} + +void pListView::onTick(QTreeWidgetItem *item) { + unsigned row = item->data(0, Qt::UserRole).toUInt(); + bool checkState = checked(row); + listView.state.checked[row] = checkState; + if(locked == false && listView.onTick) listView.onTick(row); +} diff --git a/phoenix/qt/widget/progress-bar.cpp b/phoenix/qt/widget/progress-bar.cpp new file mode 100755 index 00000000..8178bb66 --- /dev/null +++ b/phoenix/qt/widget/progress-bar.cpp @@ -0,0 +1,26 @@ +Geometry pProgressBar::minimumGeometry() { + return { 0, 0, 0, 25 }; +} + +void pProgressBar::setPosition(unsigned position) { + qtProgressBar->setValue(position); +} + +void pProgressBar::constructor() { + qtWidget = qtProgressBar = new QProgressBar; + qtProgressBar->setRange(0, 100); + qtProgressBar->setTextVisible(false); + + pWidget::synchronizeState(); + setPosition(progressBar.state.position); +} + +void pProgressBar::destructor() { + delete qtProgressBar; + qtWidget = qtProgressBar = 0; +} + +void pProgressBar::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/qt/widget/radio-box.cpp b/phoenix/qt/widget/radio-box.cpp new file mode 100755 index 00000000..b6bb219a --- /dev/null +++ b/phoenix/qt/widget/radio-box.cpp @@ -0,0 +1,64 @@ +bool pRadioBox::checked() { + return qtRadioBox->isChecked(); +} + +Geometry pRadioBox::minimumGeometry() { + Geometry geometry = pFont::geometry(qtWidget->font(), radioBox.state.text); + return { 0, 0, geometry.width + 26, geometry.height + 6 }; +} + +void pRadioBox::setChecked() { + locked = true; + for(auto &item : radioBox.state.group) { + bool checkState = item.p.qtRadioBox == qtRadioBox; + item.state.checked = checkState; + item.p.qtRadioBox->setChecked(checkState); + } + locked = false; +} + +void pRadioBox::setGroup(const reference_array &group) { + locked = true; + if(qtGroup) { + delete qtGroup; + qtGroup = 0; + } + if(group.size() > 0 && qtRadioBox == group[0].p.qtRadioBox) { + qtGroup = new QButtonGroup; + for(auto &item : group) qtGroup->addButton(item.p.qtRadioBox); + setChecked(); + } + locked = false; +} + +void pRadioBox::setText(const string &text) { + qtRadioBox->setText(QString::fromUtf8(text)); +} + +void pRadioBox::constructor() { + qtWidget = qtRadioBox = new QRadioButton; + qtGroup = new QButtonGroup; + qtGroup->addButton(qtRadioBox); + qtRadioBox->setChecked(true); + connect(qtRadioBox, SIGNAL(toggled(bool)), SLOT(onTick())); + + pWidget::synchronizeState(); + setGroup(radioBox.state.group); + setText(radioBox.state.text); +} + +void pRadioBox::destructor() { + delete qtGroup; + delete qtRadioBox; + qtWidget = qtRadioBox = 0; + qtGroup = 0; +} + +void pRadioBox::orphan() { + destructor(); + constructor(); +} + +void pRadioBox::onTick() { + if(locked == false && checked() && radioBox.onTick) radioBox.onTick(); +} diff --git a/phoenix/qt/widget/text-edit.cpp b/phoenix/qt/widget/text-edit.cpp new file mode 100755 index 00000000..ed168866 --- /dev/null +++ b/phoenix/qt/widget/text-edit.cpp @@ -0,0 +1,48 @@ +void pTextEdit::setCursorPosition(unsigned position) { + QTextCursor cursor = qtTextEdit->textCursor(); + unsigned lastCharacter = strlen(qtTextEdit->toPlainText().toUtf8().constData()); + cursor.setPosition(min(position, lastCharacter)); + qtTextEdit->setTextCursor(cursor); +} + +void pTextEdit::setEditable(bool editable) { + qtTextEdit->setReadOnly(!editable); +} + +void pTextEdit::setText(const string &text) { + qtTextEdit->setPlainText(QString::fromUtf8(text)); +} + +void pTextEdit::setWordWrap(bool wordWrap) { + qtTextEdit->setWordWrapMode(wordWrap ? QTextOption::WordWrap : QTextOption::NoWrap); +} + +string pTextEdit::text() { + return qtTextEdit->toPlainText().toUtf8().constData(); +} + +void pTextEdit::constructor() { + qtWidget = qtTextEdit = new QTextEdit; + connect(qtTextEdit, SIGNAL(textChanged()), SLOT(onChange())); + + pWidget::synchronizeState(); + setEditable(textEdit.state.editable); + setText(textEdit.state.text); + setWordWrap(textEdit.state.wordWrap); +} + +void pTextEdit::destructor() { + if(sizable.state.layout) sizable.state.layout->remove(textEdit); + delete qtTextEdit; + qtWidget = qtTextEdit = 0; +} + +void pTextEdit::orphan() { + destructor(); + constructor(); +} + +void pTextEdit::onChange() { + textEdit.state.text = text(); + if(textEdit.onChange) textEdit.onChange(); +} diff --git a/phoenix/qt/widget/vertical-scroll-bar.cpp b/phoenix/qt/widget/vertical-scroll-bar.cpp new file mode 100755 index 00000000..74d68ca6 --- /dev/null +++ b/phoenix/qt/widget/vertical-scroll-bar.cpp @@ -0,0 +1,43 @@ +Geometry pVerticalScrollBar::minimumGeometry() { + return { 0, 0, 15, 0 }; +} + +unsigned pVerticalScrollBar::position() { + return qtScrollBar->value(); +} + +void pVerticalScrollBar::setLength(unsigned length) { + length += length == 0; + qtScrollBar->setRange(0, length - 1); + qtScrollBar->setPageStep(length >> 3); +} + +void pVerticalScrollBar::setPosition(unsigned position) { + qtScrollBar->setValue(position); +} + +void pVerticalScrollBar::constructor() { + qtWidget = qtScrollBar = new QScrollBar(Qt::Vertical); + qtScrollBar->setRange(0, 100); + qtScrollBar->setPageStep(101 >> 3); + connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + setLength(verticalScrollBar.state.length); + setPosition(verticalScrollBar.state.position); +} + +void pVerticalScrollBar::destructor() { + delete qtScrollBar; + qtWidget = qtScrollBar = 0; +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); +} + +void pVerticalScrollBar::onChange() { + verticalScrollBar.state.position = position(); + if(verticalScrollBar.onChange) verticalScrollBar.onChange(); +} diff --git a/phoenix/qt/widget/vertical-slider.cpp b/phoenix/qt/widget/vertical-slider.cpp new file mode 100755 index 00000000..500adb07 --- /dev/null +++ b/phoenix/qt/widget/vertical-slider.cpp @@ -0,0 +1,43 @@ +Geometry pVerticalSlider::minimumGeometry() { + return { 0, 0, 20, 0 }; +} + +unsigned pVerticalSlider::position() { + return qtSlider->value(); +} + +void pVerticalSlider::setLength(unsigned length) { + length += length == 0; + qtSlider->setRange(0, length - 1); + qtSlider->setPageStep(length >> 3); +} + +void pVerticalSlider::setPosition(unsigned position) { + qtSlider->setValue(position); +} + +void pVerticalSlider::constructor() { + qtWidget = qtSlider = new QSlider(Qt::Vertical); + qtSlider->setRange(0, 100); + qtSlider->setPageStep(101 >> 3); + connect(qtSlider, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::synchronizeState(); + setLength(verticalSlider.state.length); + setPosition(verticalSlider.state.position); +} + +void pVerticalSlider::destructor() { + delete qtSlider; + qtWidget = qtSlider = 0; +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); +} + +void pVerticalSlider::onChange() { + verticalSlider.state.position = position(); + if(verticalSlider.onChange) verticalSlider.onChange(); +} diff --git a/phoenix/qt/widget/viewport.cpp b/phoenix/qt/widget/viewport.cpp new file mode 100755 index 00000000..3a6254f9 --- /dev/null +++ b/phoenix/qt/widget/viewport.cpp @@ -0,0 +1,21 @@ +uintptr_t pViewport::handle() { + return (uintptr_t)qtWidget->winId(); +} + +void pViewport::constructor() { + qtWidget = new QWidget; + qtWidget->setAttribute(Qt::WA_PaintOnScreen, true); + qtWidget->setStyleSheet("background: #000000"); + + pWidget::synchronizeState(); +} + +void pViewport::destructor() { + delete qtWidget; + qtWidget = 0; +} + +void pViewport::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/qt/widget/widget.cpp b/phoenix/qt/widget/widget.cpp new file mode 100755 index 00000000..0bc4901c --- /dev/null +++ b/phoenix/qt/widget/widget.cpp @@ -0,0 +1,52 @@ +Geometry pWidget::minimumGeometry() { + return { 0, 0, 0, 0 }; +} + +void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; + qtWidget->setEnabled(enabled); +} + +void pWidget::setFocused() { + qtWidget->setFocus(Qt::OtherFocusReason); +} + +void pWidget::setFont(const string &font) { + qtWidget->setFont(pFont::create(font)); +} + +void pWidget::setGeometry(const Geometry &geometry) { + qtWidget->setGeometry(geometry.x, geometry.y, geometry.width, geometry.height); +} + +void pWidget::setVisible(bool visible) { + if(widget.state.abstract) visible = false; + if(sizable.state.layout == 0) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; + qtWidget->setVisible(visible); +} + +void pWidget::constructor() { + if(widget.state.abstract) qtWidget = new QWidget; +} + +//pWidget::constructor() called before p{Derived}::constructor(); ergo qtWidget is not yet valid +//pWidget::synchronizeState() is called to finish construction of p{Derived}::constructor() +void pWidget::synchronizeState() { + setEnabled(widget.state.enabled); + setFont(widget.state.font); +//setVisible(widget.state.visible); +} + +void pWidget::destructor() { + if(widget.state.abstract) { + delete qtWidget; + qtWidget = 0; + } +} + +void pWidget::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/qt/window.cpp b/phoenix/qt/window.cpp new file mode 100755 index 00000000..4710e4e4 --- /dev/null +++ b/phoenix/qt/window.cpp @@ -0,0 +1,266 @@ +void pWindow::append(Layout &layout) { + Geometry geometry = window.state.geometry; + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); +} + +void pWindow::append(Menu &menu) { + if(window.state.menuFont != "") menu.p.setFont(window.state.menuFont); + else menu.p.setFont("Sans, 8"); + qtMenu->addMenu(menu.p.qtMenu); +} + +void pWindow::append(Widget &widget) { + if(widget.state.font == "") { + if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Sans, 8"); + } + widget.p.qtWidget->setParent(qtContainer); + widget.setVisible(widget.visible()); +} + +Color pWindow::backgroundColor() { + if(window.state.backgroundColorOverride) return window.state.backgroundColor; + QColor color = qtWindow->palette().color(QPalette::ColorRole::Window); + return { (uint8_t)color.red(), (uint8_t)color.green(), (uint8_t)color.blue(), (uint8_t)color.alpha() }; +} + +Geometry pWindow::frameMargin() { + unsigned menuHeight = window.state.menuVisible ? settings->menuGeometryHeight : 0; + unsigned statusHeight = window.state.statusVisible ? settings->statusGeometryHeight : 0; + if(window.state.fullScreen) return { 0, menuHeight, 0, menuHeight + statusHeight }; + return { + settings->frameGeometryX, + settings->frameGeometryY + menuHeight, + settings->frameGeometryWidth, + settings->frameGeometryHeight + menuHeight + statusHeight + }; +} + +bool pWindow::focused() { + return qtWindow->isActiveWindow() && !qtWindow->isMinimized(); +} + +Geometry pWindow::geometry() { + if(window.state.fullScreen) { + unsigned menuHeight = window.state.menuVisible ? qtMenu->height() : 0; + unsigned statusHeight = window.state.statusVisible ? qtStatus->height() : 0; + return { 0, menuHeight, OS::desktopGeometry().width, OS::desktopGeometry().height - menuHeight - statusHeight }; + } + return window.state.geometry; +} + +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + //QMenuBar::removeMenu() does not exist + qtMenu->clear(); + for(auto &menu : window.state.menu) append(menu); +} + +void pWindow::remove(Widget &widget) { + //bugfix: orphan() destroys and recreates widgets (to disassociate them from their parent); + //attempting to create widget again after QApplication::quit() crashes libQtGui + if(qtApplication) widget.p.orphan(); +} + +void pWindow::setBackgroundColor(const Color &color) { + QPalette palette; + palette.setColor(QPalette::Window, QColor(color.red, color.green, color.blue)); + qtContainer->setPalette(palette); + qtContainer->setAutoFillBackground(true); +} + +void pWindow::setFocused() { + qtWindow->raise(); + qtWindow->activateWindow(); +} + +void pWindow::setFullScreen(bool fullScreen) { + if(fullScreen == false) { + setResizable(window.state.resizable); + qtWindow->showNormal(); + qtWindow->adjustSize(); + } else { + Geometry geometry = OS::desktopGeometry(), margin = frameMargin(); + qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint); + qtContainer->setFixedSize(geometry.width - margin.width, geometry.height - margin.height); + qtWindow->showFullScreen(); + } +} + +void pWindow::setGeometry(const Geometry &geometry_) { + locked = true; + OS::processEvents(); + QApplication::syncX(); + Geometry geometry = geometry_, margin = frameMargin(); + + setResizable(window.state.resizable); + qtWindow->move(geometry.x - frameMargin().x, geometry.y - frameMargin().y); + //qtWindow->adjustSize() fails if larger than 2/3rds screen size + qtWindow->resize(qtWindow->sizeHint()); + qtWindow->setMinimumSize(1, 1); + qtContainer->setMinimumSize(1, 1); + + for(auto &layout : window.state.layout) { + geometry = geometry_; + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); + } + locked = false; +} + +void pWindow::setMenuFont(const string &font) { + qtMenu->setFont(pFont::create(font)); + for(auto &item : window.state.menu) item.p.setFont(font); +} + +void pWindow::setMenuVisible(bool visible) { + qtMenu->setVisible(visible); + setGeometry(window.state.geometry); +} + +void pWindow::setResizable(bool resizable) { + if(resizable) { + qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint); + qtContainer->setMinimumSize(window.state.geometry.width, window.state.geometry.height); + } else { + qtLayout->setSizeConstraint(QLayout::SetFixedSize); + qtContainer->setFixedSize(window.state.geometry.width, window.state.geometry.height); + } + qtStatus->setSizeGripEnabled(resizable); +} + +void pWindow::setStatusFont(const string &font) { + qtStatus->setFont(pFont::create(font)); +} + +void pWindow::setStatusText(const string &text) { + qtStatus->showMessage(QString::fromUtf8(text), 0); +} + +void pWindow::setStatusVisible(bool visible) { + qtStatus->setVisible(visible); + setGeometry(window.state.geometry); +} + +void pWindow::setTitle(const string &text) { + qtWindow->setWindowTitle(QString::fromUtf8(text)); +} + +void pWindow::setVisible(bool visible) { + locked = true; + qtWindow->setVisible(visible); + if(visible) { + updateFrameGeometry(); + setGeometry(window.state.geometry); + } + locked = false; +} + +void pWindow::setWidgetFont(const string &font) { + for(auto &item : window.state.widget) { + if(!item.state.font) item.setFont(font); + } +} + +void pWindow::constructor() { + qtWindow = new QtWindow(*this); + qtWindow->setWindowTitle(" "); + + qtLayout = new QVBoxLayout(qtWindow); + qtLayout->setMargin(0); + qtLayout->setSpacing(0); + qtWindow->setLayout(qtLayout); + + qtMenu = new QMenuBar(qtWindow); + qtMenu->setVisible(false); + qtLayout->addWidget(qtMenu); + + qtContainer = new QWidget(qtWindow); + qtContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + qtContainer->setVisible(true); + qtLayout->addWidget(qtContainer); + + qtStatus = new QStatusBar(qtWindow); + qtStatus->setSizeGripEnabled(true); + qtStatus->setVisible(false); + qtLayout->addWidget(qtStatus); + + setGeometry(window.state.geometry); + setMenuFont("Sans, 8"); + setStatusFont("Sans, 8"); +} + +void pWindow::destructor() { + delete qtStatus; + delete qtContainer; + delete qtMenu; + delete qtLayout; + delete qtWindow; +} + +void pWindow::updateFrameGeometry() { + pOS::syncX(); + QRect border = qtWindow->frameGeometry(); + QRect client = qtWindow->geometry(); + + settings->frameGeometryX = client.x() - border.x(); + settings->frameGeometryY = client.y() - border.y(); + settings->frameGeometryWidth = border.width() - client.width(); + settings->frameGeometryHeight = border.height() - client.height(); + + if(window.state.menuVisible) { + pOS::syncX(); + settings->menuGeometryHeight = qtMenu->height(); + } + + if(window.state.statusVisible) { + pOS::syncX(); + settings->statusGeometryHeight = qtStatus->height(); + } +} + +void pWindow::QtWindow::closeEvent(QCloseEvent *event) { + self.window.state.ignore = false; + event->ignore(); + if(self.window.onClose) self.window.onClose(); + if(self.window.state.ignore == false) hide(); +} + +void pWindow::QtWindow::moveEvent(QMoveEvent *event) { + if(self.locked == false && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { + self.window.state.geometry.x += event->pos().x() - event->oldPos().x(); + self.window.state.geometry.y += event->pos().y() - event->oldPos().y(); + } + + if(self.locked == false) { + if(self.window.onMove) self.window.onMove(); + } +} + +void pWindow::QtWindow::resizeEvent(QResizeEvent*) { + if(self.locked == false && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { + self.window.state.geometry.width = self.qtContainer->geometry().width(); + self.window.state.geometry.height = self.qtContainer->geometry().height(); + } + + for(auto &layout : self.window.state.layout) { + Geometry geometry = self.geometry(); + geometry.x = geometry.y = 0; + layout.setGeometry(geometry); + } + + if(self.locked == false) { + if(self.window.onSize) self.window.onSize(); + } +} + +QSize pWindow::QtWindow::sizeHint() const { + unsigned width = self.window.state.geometry.width; + unsigned height = self.window.state.geometry.height; + if(self.window.state.menuVisible) height += settings->menuGeometryHeight; + if(self.window.state.statusVisible) height += settings->statusGeometryHeight; + return QSize(width, height); +} diff --git a/phoenix/reference/action/action.cpp b/phoenix/reference/action/action.cpp new file mode 100755 index 00000000..0bc6bc3f --- /dev/null +++ b/phoenix/reference/action/action.cpp @@ -0,0 +1,8 @@ +void pAction::setEnabled(bool enabled) { +} + +void pAction::setVisible(bool visible) { +} + +void pAction::constructor() { +} diff --git a/phoenix/reference/action/check-item.cpp b/phoenix/reference/action/check-item.cpp new file mode 100755 index 00000000..26970fc8 --- /dev/null +++ b/phoenix/reference/action/check-item.cpp @@ -0,0 +1,15 @@ +bool pCheckItem::checked() { + return false; +} + +void pCheckItem::setChecked(bool checked) { +} + +void pCheckItem::setText(const string &text) { +} + +void pCheckItem::constructor() { +} + +void pCheckItem::destructor() { +} diff --git a/phoenix/reference/action/item.cpp b/phoenix/reference/action/item.cpp new file mode 100755 index 00000000..d064389b --- /dev/null +++ b/phoenix/reference/action/item.cpp @@ -0,0 +1,8 @@ +void pItem::setText(const string &text) { +} + +void pItem::constructor() { +} + +void pItem::destructor() { +} diff --git a/phoenix/reference/action/menu.cpp b/phoenix/reference/action/menu.cpp new file mode 100755 index 00000000..c2c239f2 --- /dev/null +++ b/phoenix/reference/action/menu.cpp @@ -0,0 +1,14 @@ +void pMenu::append(Action &action) { +} + +void pMenu::remove(Action &action) { +} + +void pMenu::setText(const string &text) { +} + +void pMenu::constructor() { +} + +void pMenu::destructor() { +} diff --git a/phoenix/reference/action/radio-item.cpp b/phoenix/reference/action/radio-item.cpp new file mode 100755 index 00000000..fc732e04 --- /dev/null +++ b/phoenix/reference/action/radio-item.cpp @@ -0,0 +1,18 @@ +bool pRadioItem::checked() { + return false; +} + +void pRadioItem::setChecked() { +} + +void pRadioItem::setGroup(const reference_array &group) { +} + +void pRadioItem::setText(const string &text) { +} + +void pRadioItem::constructor() { +} + +void pRadioItem::destructor() { +} diff --git a/phoenix/reference/action/separator.cpp b/phoenix/reference/action/separator.cpp new file mode 100755 index 00000000..24a45c04 --- /dev/null +++ b/phoenix/reference/action/separator.cpp @@ -0,0 +1,5 @@ +void pSeparator::constructor() { +} + +void pSeparator::destructor() { +} diff --git a/phoenix/reference/font.cpp b/phoenix/reference/font.cpp new file mode 100755 index 00000000..bfda5c06 --- /dev/null +++ b/phoenix/reference/font.cpp @@ -0,0 +1,3 @@ +Geometry pFont::geometry(const string &description, const string &text) { + return { 0, 0, 0, 0 }; +} diff --git a/phoenix/reference/message-window.cpp b/phoenix/reference/message-window.cpp new file mode 100755 index 00000000..84a287f5 --- /dev/null +++ b/phoenix/reference/message-window.cpp @@ -0,0 +1,15 @@ +MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return MessageWindow::Response::Ok; +} diff --git a/phoenix/reference/platform.cpp b/phoenix/reference/platform.cpp new file mode 100755 index 00000000..b35adcef --- /dev/null +++ b/phoenix/reference/platform.cpp @@ -0,0 +1,67 @@ +#include "platform.hpp" + +#include "font.cpp" +#include "timer.cpp" +#include "message-window.cpp" +#include "window.cpp" + +#include "action/action.cpp" +#include "action/menu.cpp" +#include "action/separator.cpp" +#include "action/item.cpp" +#include "action/check-item.cpp" +#include "action/radio-item.cpp" + +#include "widget/widget.cpp" +#include "widget/button.cpp" +#include "widget/canvas.cpp" +#include "widget/check-box.cpp" +#include "widget/combo-box.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-box.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +Geometry pOS::availableGeometry() { + return { 0, 0, 0, 0 }; +} + +Geometry pOS::desktopGeometry() { + return { 0, 0, 0, 0 }; +} + +string pOS::fileLoad(Window &parent, const string &path, const lstring &filter) { + return ""; +} + +string pOS::fileSave(Window &parent, const string &path, const lstring &filter) { + return ""; +} + +string pOS::folderSelect(Window &parent, const string &path) { + return ""; +} + +void pOS::main() { +} + +bool pOS::pendingEvents() { + return false; +} + +void pOS::processEvents() { +} + +void pOS::quit() { +} + +void pOS::initialize() { +} diff --git a/phoenix/reference/platform.hpp b/phoenix/reference/platform.hpp new file mode 100755 index 00000000..fccb99ed --- /dev/null +++ b/phoenix/reference/platform.hpp @@ -0,0 +1,357 @@ +struct pFont; +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +struct pFont { + static Geometry geometry(const string &description, const string &text); +}; + +struct pObject { + Object &object; + bool locked; + + pObject(Object &object) : object(object), locked(locked) {} + virtual ~pObject() {} + + void constructor() {} + void destructor() {} +}; + +struct pOS : public pObject { + static Geometry availableGeometry(); + static Geometry desktopGeometry(); + static string fileLoad(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); +}; + +struct pTimer : public pObject { + Timer &timer; + + void setEnabled(bool enabled); + void setInterval(unsigned milliseconds); + + pTimer(Timer &timer) : pObject(timer), timer(timer) {} + void constructor(); +}; + +struct pMessageWindow : public pObject { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + +struct pWindow : public pObject { + Window &window; + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + bool focused(); + Geometry frameMargin(); + Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFocused(); + void setFullScreen(bool fullScreen); + void setGeometry(const Geometry &geometry); + void setMenuFont(const string &font); + void setMenuVisible(bool visible); + void setResizable(bool resizable); + void setStatusFont(const string &font); + void setStatusText(const string &text); + void setStatusVisible(bool visible); + void setTitle(const string &text); + void setVisible(bool visible); + void setWidgetFont(const string &font); + + pWindow(Window &window) : pObject(window), window(window) {} + void constructor(); +}; + +struct pAction : public pObject { + Action &action; + + void setEnabled(bool enabled); + void setVisible(bool visible); + + pAction(Action &action) : pObject(action), action(action) {} + void constructor(); +}; + +struct pMenu : public pAction { + Menu &menu; + + void append(Action &action); + void remove(Action &action); + void setText(const string &text); + + pMenu(Menu &menu) : pAction(menu), menu(menu) {} + void constructor(); + void destructor(); +}; + +struct pSeparator : public pAction { + Separator &separator; + + pSeparator(Separator &separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); +}; + +struct pItem : public pAction { + Item &item; + + void setText(const string &text); + + pItem(Item &item) : pAction(item), item(item) {} + void constructor(); + void destructor(); +}; + +struct pCheckItem : public pAction { + CheckItem &checkItem; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} + void constructor(); + void destructor(); +}; + +struct pRadioItem : public pAction { + RadioItem &radioItem; + + bool checked(); + void setChecked(); + void setGroup(const reference_array &group); + void setText(const string &text); + + pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} + void constructor(); + void destructor(); +}; + +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { + Widget &widget; + + bool enabled(); + Geometry minimumGeometry(); + void setEnabled(bool enabled); + void setFocused(); + void setFont(const string &font); + void setGeometry(const Geometry &geometry); + void setVisible(bool visible); + + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} + void constructor(); +}; + +struct pButton : public pWidget { + Button &button; + + void setText(const string &text); + + pButton(Button &button) : pWidget(button), button(button) {} + void constructor(); +}; + +struct pCanvas : public pWidget { + Canvas &canvas; + + void setSize(const Size &size); + void update(); + + pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); +}; + +struct pCheckBox : public pWidget { + CheckBox &checkBox; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} + void constructor(); +}; + +struct pComboBox : public pWidget { + ComboBox &comboBox; + + void append(const string &text); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} + void constructor(); +}; + +struct pHexEdit : public pWidget { + HexEdit &hexEdit; + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} + void constructor(); +}; + +struct pHorizontalScrollBar : public pWidget { + HorizontalScrollBar &horizontalScrollBar; + + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} + void constructor(); +}; + +struct pHorizontalSlider : public pWidget { + HorizontalSlider &horizontalSlider; + + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); +}; + +struct pLabel : public pWidget { + Label &label; + + void setText(const string &text); + + pLabel(Label &label) : pWidget(label), label(label) {} + void constructor(); +}; + +struct pLineEdit : public pWidget { + LineEdit &lineEdit; + + void setEditable(bool editable); + void setText(const string &text); + string text(); + + pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} + void constructor(); +}; + +struct pListView : public pWidget { + ListView &listView; + + void append(const lstring &text); + void autoSizeColumns(); + bool checked(unsigned row); + void modify(unsigned row, const lstring &text); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable); + void setChecked(unsigned row, bool checked); + void setHeaderText(const lstring &text); + void setHeaderVisible(bool visible); + void setSelected(bool selected); + void setSelection(unsigned row); + + pListView(ListView &listView) : pWidget(listView), listView(listView) {} + void constructor(); +}; + +struct pProgressBar : public pWidget { + ProgressBar &progressBar; + + void setPosition(unsigned position); + + pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); +}; + +struct pRadioBox : public pWidget { + RadioBox &radioBox; + + bool checked(); + void setChecked(); + void setGroup(const reference_array &group); + void setText(const string &text); + + pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} + void constructor(); +}; + +struct pTextEdit : public pWidget { + TextEdit &textEdit; + + void setCursorPosition(unsigned position); + void setEditable(bool editable); + void setText(const string &text); + void setWordWrap(bool wordWrap); + string text(); + + pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} + void constructor(); +}; + +struct pVerticalScrollBar : public pWidget { + VerticalScrollBar &verticalScrollBar; + + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} + void constructor(); +}; + +struct pVerticalSlider : public pWidget { + VerticalSlider &verticalSlider; + + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); +}; + +struct pViewport : public pWidget { + Viewport &viewport; + + uintptr_t handle(); + + pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); +}; diff --git a/phoenix/reference/timer.cpp b/phoenix/reference/timer.cpp new file mode 100755 index 00000000..6cbe571a --- /dev/null +++ b/phoenix/reference/timer.cpp @@ -0,0 +1,8 @@ +void pTimer::setEnabled(bool enabled) { +} + +void pTimer::setInterval(unsigned milliseconds) { +} + +void pTimer::constructor() { +} diff --git a/phoenix/reference/widget/button.cpp b/phoenix/reference/widget/button.cpp new file mode 100755 index 00000000..a56410c1 --- /dev/null +++ b/phoenix/reference/widget/button.cpp @@ -0,0 +1,5 @@ +void pButton::setText(const string &text) { +} + +void pButton::constructor() { +} diff --git a/phoenix/reference/widget/canvas.cpp b/phoenix/reference/widget/canvas.cpp new file mode 100755 index 00000000..953cfa77 --- /dev/null +++ b/phoenix/reference/widget/canvas.cpp @@ -0,0 +1,8 @@ +void pCanvas::setSize(const Size &size) { +} + +void pCanvas::update() { +} + +void pCanvas::constructor() { +} diff --git a/phoenix/reference/widget/check-box.cpp b/phoenix/reference/widget/check-box.cpp new file mode 100755 index 00000000..c5aec216 --- /dev/null +++ b/phoenix/reference/widget/check-box.cpp @@ -0,0 +1,12 @@ +bool pCheckBox::checked() { + return false; +} + +void pCheckBox::setChecked(bool checked) { +} + +void pCheckBox::setText(const string &text) { +} + +void pCheckBox::constructor() { +} diff --git a/phoenix/reference/widget/combo-box.cpp b/phoenix/reference/widget/combo-box.cpp new file mode 100755 index 00000000..a880eb09 --- /dev/null +++ b/phoenix/reference/widget/combo-box.cpp @@ -0,0 +1,15 @@ +void pComboBox::append(const string &text) { +} + +void pComboBox::reset() { +} + +unsigned pComboBox::selection() { + return 0; +} + +void pComboBox::setSelection(unsigned row) { +} + +void pComboBox::constructor() { +} diff --git a/phoenix/reference/widget/hex-edit.cpp b/phoenix/reference/widget/hex-edit.cpp new file mode 100755 index 00000000..40bf9f5d --- /dev/null +++ b/phoenix/reference/widget/hex-edit.cpp @@ -0,0 +1,17 @@ +void pHexEdit::setColumns(unsigned columns) { +} + +void pHexEdit::setLength(unsigned length) { +} + +void pHexEdit::setOffset(unsigned offset) { +} + +void pHexEdit::setRows(unsigned rows) { +} + +void pHexEdit::update() { +} + +void pHexEdit::constructor() { +} diff --git a/phoenix/reference/widget/horizontal-scroll-bar.cpp b/phoenix/reference/widget/horizontal-scroll-bar.cpp new file mode 100755 index 00000000..352b3393 --- /dev/null +++ b/phoenix/reference/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,12 @@ +unsigned pHorizontalScrollBar::position() { + return 0; +} + +void pHorizontalScrollBar::setLength(unsigned length) { +} + +void pHorizontalScrollBar::setPosition(unsigned position) { +} + +void pHorizontalScrollBar::constructor() { +} diff --git a/phoenix/reference/widget/horizontal-slider.cpp b/phoenix/reference/widget/horizontal-slider.cpp new file mode 100755 index 00000000..0a4a8392 --- /dev/null +++ b/phoenix/reference/widget/horizontal-slider.cpp @@ -0,0 +1,12 @@ +unsigned pHorizontalSlider::position() { + return 0; +} + +void pHorizontalSlider::setLength(unsigned length) { +} + +void pHorizontalSlider::setPosition(unsigned position) { +} + +void pHorizontalSlider::constructor() { +} diff --git a/phoenix/reference/widget/label.cpp b/phoenix/reference/widget/label.cpp new file mode 100755 index 00000000..25600d2a --- /dev/null +++ b/phoenix/reference/widget/label.cpp @@ -0,0 +1,5 @@ +void pLabel::setText(const string &text) { +} + +void pLabel::constructor() { +} diff --git a/phoenix/reference/widget/line-edit.cpp b/phoenix/reference/widget/line-edit.cpp new file mode 100755 index 00000000..96b9ac6c --- /dev/null +++ b/phoenix/reference/widget/line-edit.cpp @@ -0,0 +1,11 @@ +void pLineEdit::setEditable(bool editable) { +} + +void pLineEdit::setText(const string &text) { +} + +string pLineEdit::text() { +} + +void pLineEdit::constructor() { +} diff --git a/phoenix/reference/widget/list-view.cpp b/phoenix/reference/widget/list-view.cpp new file mode 100755 index 00000000..3170f6bb --- /dev/null +++ b/phoenix/reference/widget/list-view.cpp @@ -0,0 +1,43 @@ +void pListView::append(const lstring &text) { +} + +void pListView::autoSizeColumns() { +} + +bool pListView::checked(unsigned row) { +} + +void pListView::modify(unsigned row, const lstring &text) { +} + +void pListView::reset() { +} + +bool pListView::selected() { + return false; +} + +unsigned pListView::selection() { + return 0; +} + +void pListView::setCheckable(bool checkable) { +} + +void pListView::setChecked(unsigned row, bool checked) { +} + +void pListView::setHeaderText(const lstring &text) { +} + +void pListView::setHeaderVisible(bool visible) { +} + +void pListView::setSelected(bool selected) { +} + +void pListView::setSelection(unsigned row) { +} + +void pListView::constructor() { +} diff --git a/phoenix/reference/widget/progress-bar.cpp b/phoenix/reference/widget/progress-bar.cpp new file mode 100755 index 00000000..b4905a85 --- /dev/null +++ b/phoenix/reference/widget/progress-bar.cpp @@ -0,0 +1,5 @@ +void pProgressBar::setPosition(unsigned position) { +} + +void pProgressBar::constructor() { +} diff --git a/phoenix/reference/widget/radio-box.cpp b/phoenix/reference/widget/radio-box.cpp new file mode 100755 index 00000000..603e2442 --- /dev/null +++ b/phoenix/reference/widget/radio-box.cpp @@ -0,0 +1,15 @@ +bool pRadioBox::checked() { + return false; +} + +void pRadioBox::setChecked() { +} + +void pRadioBox::setGroup(const reference_array &group) { +} + +void pRadioBox::setText(const string &text) { +} + +void pRadioBox::constructor() { +} diff --git a/phoenix/reference/widget/text-edit.cpp b/phoenix/reference/widget/text-edit.cpp new file mode 100755 index 00000000..74121b2d --- /dev/null +++ b/phoenix/reference/widget/text-edit.cpp @@ -0,0 +1,17 @@ +void pTextEdit::setCursorPosition(unsigned position) { +} + +void pTextEdit::setEditable(bool editable) { +} + +void pTextEdit::setText(const string &text) { +} + +void pTextEdit::setWordWrap(bool wordWrap) { +} + +string pTextEdit::text() { +} + +void pTextEdit::constructor() { +} diff --git a/phoenix/reference/widget/vertical-scroll-bar.cpp b/phoenix/reference/widget/vertical-scroll-bar.cpp new file mode 100755 index 00000000..26795248 --- /dev/null +++ b/phoenix/reference/widget/vertical-scroll-bar.cpp @@ -0,0 +1,12 @@ +unsigned pVerticalScrollBar::position() { + return 0; +} + +void pVerticalScrollBar::setLength(unsigned length) { +} + +void pVerticalScrollBar::setPosition(unsigned position) { +} + +void pVerticalScrollBar::constructor() { +} diff --git a/phoenix/reference/widget/vertical-slider.cpp b/phoenix/reference/widget/vertical-slider.cpp new file mode 100755 index 00000000..a6d8ae00 --- /dev/null +++ b/phoenix/reference/widget/vertical-slider.cpp @@ -0,0 +1,12 @@ +unsigned pVerticalSlider::position() { + return 0; +} + +void pVerticalSlider::setLength(unsigned length) { +} + +void pVerticalSlider::setPosition(unsigned position) { +} + +void pVerticalSlider::constructor() { +} diff --git a/phoenix/reference/widget/viewport.cpp b/phoenix/reference/widget/viewport.cpp new file mode 100755 index 00000000..9d398438 --- /dev/null +++ b/phoenix/reference/widget/viewport.cpp @@ -0,0 +1,6 @@ +uintptr_t pViewport::handle() { + return 0; +} + +void pViewport::constructor() { +} diff --git a/phoenix/reference/widget/widget.cpp b/phoenix/reference/widget/widget.cpp new file mode 100755 index 00000000..49a6c79e --- /dev/null +++ b/phoenix/reference/widget/widget.cpp @@ -0,0 +1,25 @@ +bool pWidget::enabled() { + return false; +} + +Geometry pWidget::minimumGeometry() { + return { 0, 0, 0, 0 }; +} + +void pWidget::setEnabled(bool enabled) { +} + +void pWidget::setFocused() { +} + +void pWidget::setFont(const string &font) { +} + +void pWidget::setGeometry(const Geometry &geometry) { +} + +void pWidget::setVisible(bool visible) { +} + +void pWidget::constructor() { +} diff --git a/phoenix/reference/window.cpp b/phoenix/reference/window.cpp new file mode 100755 index 00000000..a865b619 --- /dev/null +++ b/phoenix/reference/window.cpp @@ -0,0 +1,75 @@ +void pWindow::append(Layout &layout) { +} + +void pWindow::append(Menu &menu) { +} + +void pWindow::append(Widget &widget) { +} + +Color pWindow::backgroundColor() { + return { 0, 0, 0, 255 }; +} + +bool pWindow::focused() { + return false; +} + +Geometry pWindow::frameMargin() { + return { 0, 0, 0, 0 }; +} + +Geometry pWindow::geometry() { + return { 0, 0, 0, 0 }; +} + +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { +} + +void pWindow::remove(Widget &widget) { +} + +void pWindow::setBackgroundColor(const Color &color) { +} + +void pWindow::setFocused() { +} + +void pWindow::setFullScreen(bool fullScreen) { +} + +void pWindow::setGeometry(const Geometry &geometry) { +} + +void pWindow::setMenuFont(const string &font) { +} + +void pWindow::setMenuVisible(bool visible) { +} + +void pWindow::setResizable(bool resizable) { +} + +void pWindow::setStatusFont(const string &font) { +} + +void pWindow::setStatusText(const string &text) { +} + +void pWindow::setStatusVisible(bool visible) { +} + +void pWindow::setTitle(const string &text) { +} + +void pWindow::setVisible(bool visible) { +} + +void pWindow::setWidgetFont(const string &font) { +} + +void pWindow::constructor() { +} diff --git a/phoenix/sync.sh b/phoenix/sync.sh new file mode 100755 index 00000000..40ee3d98 --- /dev/null +++ b/phoenix/sync.sh @@ -0,0 +1,9 @@ +synchronize() { + if [ -d ../"$1" ]; then + test -d "$1" && rm -r "$1" + cp -r ../"$1" ./"$1" + fi +} + +synchronize "nall" +rm -r nall/test diff --git a/phoenix/windows/action/action.cpp b/phoenix/windows/action/action.cpp new file mode 100755 index 00000000..b80208d1 --- /dev/null +++ b/phoenix/windows/action/action.cpp @@ -0,0 +1,12 @@ +void pAction::setEnabled(bool enabled) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pAction::setVisible(bool visible) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pAction::constructor() { + parentMenu = 0; + parentWindow = 0; +} diff --git a/phoenix/windows/action/check-item.cpp b/phoenix/windows/action/check-item.cpp new file mode 100755 index 00000000..195deabd --- /dev/null +++ b/phoenix/windows/action/check-item.cpp @@ -0,0 +1,18 @@ +bool pCheckItem::checked() { + return checkItem.state.checked; +} + +void pCheckItem::setChecked(bool checked) { + if(parentMenu) CheckMenuItem(parentMenu->p.hmenu, id, checked ? MF_CHECKED : MF_UNCHECKED); +} + +void pCheckItem::setText(const string &text) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pCheckItem::constructor() { +} + +void pCheckItem::destructor() { + if(parentMenu) parentMenu->remove(checkItem); +} diff --git a/phoenix/windows/action/item.cpp b/phoenix/windows/action/item.cpp new file mode 100755 index 00000000..2e24e6e9 --- /dev/null +++ b/phoenix/windows/action/item.cpp @@ -0,0 +1,10 @@ +void pItem::setText(const string &text) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pItem::constructor() { +} + +void pItem::destructor() { + if(parentMenu) parentMenu->remove(item); +} diff --git a/phoenix/windows/action/menu.cpp b/phoenix/windows/action/menu.cpp new file mode 100755 index 00000000..4e060955 --- /dev/null +++ b/phoenix/windows/action/menu.cpp @@ -0,0 +1,62 @@ +void pMenu::append(Action &action) { + action.p.parentMenu = &menu; + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pMenu::remove(Action &action) { + if(parentWindow) parentWindow->p.updateMenu(); + action.p.parentMenu = 0; +} + +void pMenu::setText(const string &text) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pMenu::constructor() { + hmenu = 0; +} + +//Windows actions lack the ability to toggle visibility. +//To support this, menus must be destroyed and recreated when toggling any action's visibility. +void pMenu::update(Window &parentWindow, Menu *parentMenu) { + this->parentMenu = parentMenu; + this->parentWindow = &parentWindow; + + if(hmenu) DestroyMenu(hmenu); + hmenu = CreatePopupMenu(); + + for(auto &action : menu.state.action) { + action.p.parentMenu = &menu; + action.p.parentWindow = &parentWindow; + + unsigned enabled = action.state.enabled ? 0 : MF_GRAYED; + if(dynamic_cast(&action)) { + Menu &item = (Menu&)action; + item.p.update(parentWindow, &menu); + AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)item.p.hmenu, utf16_t(item.state.text)); + } else if(dynamic_cast(&action)) { + Separator &item = (Separator&)action; + if(action.state.visible) AppendMenu(hmenu, MF_SEPARATOR | enabled, item.p.id, L""); + } else if(dynamic_cast(&action)) { + Item &item = (Item&)action; + if(action.state.visible) AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); + } else if(dynamic_cast(&action)) { + CheckItem &item = (CheckItem&)action; + if(action.state.visible) AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); + if(item.state.checked) item.setChecked(); + } else if(dynamic_cast(&action)) { + RadioItem &item = (RadioItem&)action; + if(action.state.visible) AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); + if(item.state.checked) item.setChecked(); + } + } +} + +void pMenu::destructor() { + if(parentMenu) { + parentMenu->remove(menu); + } else if(parentWindow) { + //belongs to window's main menubar + parentWindow->remove(menu); + } +} diff --git a/phoenix/windows/action/radio-item.cpp b/phoenix/windows/action/radio-item.cpp new file mode 100755 index 00000000..b5399799 --- /dev/null +++ b/phoenix/windows/action/radio-item.cpp @@ -0,0 +1,26 @@ +bool pRadioItem::checked() { + return radioItem.state.checked; +} + +void pRadioItem::setChecked() { + for(auto &item : radioItem.state.group) { + //CheckMenuRadioItem takes: lo, hi, id; checking only id when lo <= id <= hi + //phoenix does not force IDs to be linear, so to uncheck id, we use: lo == hi == id + 1 (out of range) + //to check id, we use: lo == hi == id (only ID, but in range) + if(item.p.parentMenu) CheckMenuRadioItem(item.p.parentMenu->p.hmenu, item.p.id, item.p.id, item.p.id + (id != item.p.id), MF_BYCOMMAND); + } +} + +void pRadioItem::setGroup(const reference_array &group) { +} + +void pRadioItem::setText(const string &text) { + if(parentWindow) parentWindow->p.updateMenu(); +} + +void pRadioItem::constructor() { +} + +void pRadioItem::destructor() { + if(parentMenu) parentMenu->remove(radioItem); +} diff --git a/phoenix/windows/action/separator.cpp b/phoenix/windows/action/separator.cpp new file mode 100755 index 00000000..fac38eca --- /dev/null +++ b/phoenix/windows/action/separator.cpp @@ -0,0 +1,6 @@ +void pSeparator::constructor() { +} + +void pSeparator::destructor() { + if(parentMenu) parentMenu->remove(separator); +} diff --git a/phoenix/windows/font.cpp b/phoenix/windows/font.cpp new file mode 100755 index 00000000..de42f24d --- /dev/null +++ b/phoenix/windows/font.cpp @@ -0,0 +1,44 @@ +Geometry pFont::geometry(const string &description, const string &text) { + HFONT hfont = pFont::create(description); + Geometry geometry = pFont::geometry(hfont, text); + pFont::free(hfont); + return geometry; +} + +HFONT pFont::create(const string &description) { + lstring part; + part.split(",", description); + for(auto &item : part) item.trim(" "); + + string family = "Sans"; + unsigned size = 8u; + bool bold = false; + bool italic = false; + + if(part[0] != "") family = part[0]; + if(part.size() >= 2) size = decimal(part[1]); + if(part.size() >= 3) bold = part[2].position("Bold"); + if(part.size() >= 3) italic = part[2].position("Italic"); + + return CreateFont( + -(size * 96.0 / 72.0 + 0.5), + 0, 0, 0, bold == false ? FW_NORMAL : FW_BOLD, italic, 0, 0, 0, 0, 0, 0, 0, + utf16_t(family) + ); +} + +void pFont::free(HFONT hfont) { + DeleteObject(hfont); +} + +Geometry pFont::geometry(HFONT hfont, const string &text_) { + //temporary fix: empty text string returns height of zero; bad for eg Button height + string text = (text_ == "" ? " " : text_); + + HDC hdc = GetDC(0); + SelectObject(hdc, hfont); + RECT rc = { 0, 0, 0, 0 }; + DrawText(hdc, utf16_t(text), -1, &rc, DT_CALCRECT); + ReleaseDC(0, hdc); + return { 0, 0, rc.right, rc.bottom }; +} diff --git a/phoenix/windows/message-window.cpp b/phoenix/windows/message-window.cpp new file mode 100755 index 00000000..45008a95 --- /dev/null +++ b/phoenix/windows/message-window.cpp @@ -0,0 +1,41 @@ +static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, UINT response) { + if(response == IDOK) return MessageWindow::Response::Ok; + if(response == IDCANCEL) return MessageWindow::Response::Cancel; + if(response == IDYES) return MessageWindow::Response::Yes; + if(response == IDNO) return MessageWindow::Response::No; + if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + UINT flags = MB_ICONINFORMATION; + if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; + return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); +} + +MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + UINT flags = MB_ICONQUESTION; + if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; + return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); +} + +MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + UINT flags = MB_ICONWARNING; + if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; + return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); +} + +MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + UINT flags = MB_ICONERROR; + if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; + return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); +} diff --git a/phoenix/windows/object.cpp b/phoenix/windows/object.cpp new file mode 100755 index 00000000..8165306f --- /dev/null +++ b/phoenix/windows/object.cpp @@ -0,0 +1,13 @@ +array pObject::objects; + +pObject::pObject(Object &object) : object(object) { + static unsigned uniqueId = 100; + objects.append(this); + id = uniqueId++; + locked = false; +} + +pObject* pObject::find(unsigned id) { + for(auto &item : objects) if(item->id == id) return item; + return 0; +} diff --git a/phoenix/windows/phoenix.Manifest b/phoenix/windows/phoenix.Manifest new file mode 100755 index 00000000..71013ffe --- /dev/null +++ b/phoenix/windows/phoenix.Manifest @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/phoenix/windows/phoenix.rc b/phoenix/windows/phoenix.rc new file mode 100755 index 00000000..89fb8dc2 --- /dev/null +++ b/phoenix/windows/phoenix.rc @@ -0,0 +1 @@ +1 24 "phoenix.Manifest" diff --git a/phoenix/windows/platform.cpp b/phoenix/windows/platform.cpp new file mode 100755 index 00000000..9b4fbdd1 --- /dev/null +++ b/phoenix/windows/platform.cpp @@ -0,0 +1,481 @@ +#include "platform.hpp" + +#include "object.cpp" +#include "font.cpp" +#include "timer.cpp" +#include "message-window.cpp" +#include "window.cpp" + +#include "action/action.cpp" +#include "action/menu.cpp" +#include "action/separator.cpp" +#include "action/item.cpp" +#include "action/check-item.cpp" +#include "action/radio-item.cpp" + +#include "widget/widget.cpp" +#include "widget/button.cpp" +#include "widget/canvas.cpp" +#include "widget/check-box.cpp" +#include "widget/combo-box.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-box.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM); +static void OS_processDialogMessage(MSG&); +static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM); + +Geometry pOS::availableGeometry() { + RECT rc; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); + return { rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top }; +} + +Geometry pOS::desktopGeometry() { + return { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) }; +} + +static string pOS_fileDialog(bool save, Window &parent, const string &path, const lstring &filter) { + string dir = path; + dir.replace("/", "\\"); + + string filterList; + for(auto &filterItem : filter) { + lstring part; + part.split("(", filterItem); + if(part.size() != 2) continue; + part[1].rtrim<1>(")"); + part[1].replace(" ", ""); + part[1].transform(",", ";"); + filterList.append(string(filterItem, "\t", part[1], "\t")); + } + + utf16_t wfilter(filterList); + utf16_t wdir(dir); + wchar_t wfilename[PATH_MAX + 1] = L""; + + wchar_t *p = wfilter; + while(*p != L'\0') { + if(*p == L'\t') *p = L'\0'; + p++; + } + + OPENFILENAME ofn; + memset(&ofn, 0, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = &parent != &Window::None ? parent.p.hwnd : 0; + ofn.lpstrFilter = wfilter; + ofn.lpstrInitialDir = wdir; + ofn.lpstrFile = wfilename; + ofn.nMaxFile = PATH_MAX; + ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = L""; + + bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)); + if(result == false) return ""; + string name = (const char*)utf8_t(wfilename); + name.transform("\\", "/"); + return name; +} + +string pOS::fileLoad(Window &parent, const string &path, const lstring &filter) { + return pOS_fileDialog(false, parent, path, filter); +} + +string pOS::fileSave(Window &parent, const string &path, const lstring &filter) { + return pOS_fileDialog(true, parent, path, filter); +} + +string pOS::folderSelect(Window &parent, const string &path) { + wchar_t wfilename[PATH_MAX + 1] = L""; + BROWSEINFO bi; + bi.hwndOwner = &parent != &Window::None ? parent.p.hwnd : 0; + bi.pidlRoot = NULL; + bi.pszDisplayName = wfilename; + bi.lpszTitle = L""; + bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; + bi.lpfn = NULL; + bi.lParam = 0; + bi.iImage = 0; + bool result = false; + LPITEMIDLIST pidl = SHBrowseForFolder(&bi); + if(pidl) { + if(SHGetPathFromIDList(pidl, wfilename)) { + result = true; + IMalloc *imalloc = 0; + if(SUCCEEDED(SHGetMalloc(&imalloc))) { + imalloc->Free(pidl); + imalloc->Release(); + } + } + } + if(result == false) return ""; + string name = (const char*)utf8_t(wfilename); + if(name == "") return ""; + name.transform("\\", "/"); + if(name.endswith("/") == false) name.append("/"); + return name; +} + +void pOS::main() { + MSG msg; + while(GetMessage(&msg, 0, 0, 0)) { + OS_processDialogMessage(msg); + } +} + +bool pOS::pendingEvents() { + MSG msg; + return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); +} + +void pOS::processEvents() { + while(pendingEvents()) { + MSG msg; + if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + OS_processDialogMessage(msg); + } + } +} + +void OS_processDialogMessage(MSG &msg) { + if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) { + OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + + if(!IsDialogMessage(GetForegroundWindow(), &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void pOS::quit() { + PostQuitMessage(0); +} + +void pOS::initialize() { + CoInitialize(0); + InitCommonControls(); + + WNDCLASS wc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2)); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = OS_windowProc; + wc.lpszClassName = L"phoenix_window"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Canvas_windowProc; + wc.lpszClassName = L"phoenix_canvas"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Label_windowProc; + wc.lpszClassName = L"phoenix_label"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Viewport_windowProc; + wc.lpszClassName = L"phoenix_viewport"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); +} + +static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + if(msg == WM_KEYDOWN) { + GUITHREADINFO info; + memset(&info, 0, sizeof(GUITHREADINFO)); + info.cbSize = sizeof(GUITHREADINFO); + GetGUIThreadInfo(GetCurrentThreadId(), &info); + Object *object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); + if(object == 0) return; + if(dynamic_cast(object)) { + ListView &listView = (ListView&)*object; + if(wparam == VK_RETURN) { + if(listView.onActivate) listView.onActivate(); + } + } else if(dynamic_cast(object)) { + LineEdit &lineEdit = (LineEdit&)*object; + if(wparam == VK_RETURN) { + if(lineEdit.onActivate) lineEdit.onActivate(); + } + } + } +} + +static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!object || !dynamic_cast(object)) return DefWindowProc(hwnd, msg, wparam, lparam); + Window &window = (Window&)*object; + + switch(msg) { + case WM_CLOSE: { + window.state.ignore = false; + if(window.onClose) window.onClose(); + if(window.state.ignore == false) window.setVisible(false); + return TRUE; + } + + case WM_MOVE: { + if(window.p.locked) break; + + Geometry geometry = window.geometry(); + window.state.geometry.x = geometry.x; + window.state.geometry.y = geometry.y; + + if(window.onMove) window.onMove(); + break; + } + + case WM_SIZE: { + if(window.p.locked) break; + SetWindowPos(window.p.hstatus, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED); + + Geometry geometry = window.geometry(); + window.state.geometry.width = geometry.width; + window.state.geometry.height = geometry.height; + + for(auto &layout : window.state.layout) { + Geometry geom = window.geometry(); + geom.x = geom.y = 0; + layout.setGeometry(geom); + } + + if(window.onSize) window.onSize(); + break; + } + + case WM_GETMINMAXINFO: { + MINMAXINFO *mmi = (MINMAXINFO*)lparam; + //mmi->ptMinTrackSize.x = 256 + window.p.frameMargin().width; + //mmi->ptMinTrackSize.y = 256 + window.p.frameMargin().height; + //return TRUE; + break; + } + + case WM_ERASEBKGND: { + if(window.p.brush == 0) break; + RECT rc; + GetClientRect(window.p.hwnd, &rc); + PAINTSTRUCT ps; + BeginPaint(window.p.hwnd, &ps); + FillRect(ps.hdc, &rc, window.p.brush); + EndPaint(window.p.hwnd, &ps); + return TRUE; + } + + case WM_CTLCOLORBTN: + case WM_CTLCOLORSTATIC: { + Object *object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA); + if(object && window.p.brush) { + HDC hdc = (HDC)wparam; + SetBkColor((HDC)wparam, window.p.brushColor); + return (INT_PTR)window.p.brush; + } + break; + } + + case WM_COMMAND: { + unsigned id = LOWORD(wparam); + HWND control = GetDlgItem(window.p.hwnd, id); + if(control == 0) { + pObject *object = (pObject*)pObject::find(id); + if(!object) break; + if(dynamic_cast(object)) { + Item &item = ((pItem*)object)->item; + if(item.onTick) item.onTick(); + } else if(dynamic_cast(object)) { + CheckItem &checkItem = ((pCheckItem*)object)->checkItem; + checkItem.setChecked(!checkItem.state.checked); + if(checkItem.onTick) checkItem.onTick(); + } else if(dynamic_cast(object)) { + RadioItem &radioItem = ((pRadioItem*)object)->radioItem; + if(radioItem.state.checked == false) { + radioItem.setChecked(); + if(radioItem.onTick) radioItem.onTick(); + } + } + } else { + Object *object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA); + if(!object) break; + if(dynamic_cast(object)) { + Button &button = (Button&)*object; + if(button.onTick) button.onTick(); + } else if(dynamic_cast(object)) { + CheckBox &checkBox = (CheckBox&)*object; + checkBox.setChecked(!checkBox.state.checked); + if(checkBox.onTick) checkBox.onTick(); + } else if(dynamic_cast(object)) { + ComboBox &comboBox = (ComboBox&)*object; + if(HIWORD(wparam) == CBN_SELCHANGE) { + if(comboBox.state.selection != comboBox.selection()) { + comboBox.state.selection = comboBox.selection(); + if(comboBox.onChange) comboBox.onChange(); + } + } + } else if(dynamic_cast(object)) { + LineEdit &lineEdit = (LineEdit&)*object; + if(HIWORD(wparam) == EN_CHANGE) { + if(lineEdit.p.locked == false && lineEdit.onChange) lineEdit.onChange(); + } + } else if(dynamic_cast(object)) { + RadioBox &radioBox = (RadioBox&)*object; + if(radioBox.state.checked == false) { + radioBox.setChecked(); + if(radioBox.onTick) radioBox.onTick(); + } + } else if(dynamic_cast(object)) { + TextEdit &textEdit = (TextEdit&)*object; + if(HIWORD(wparam) == EN_CHANGE) { + if(textEdit.p.locked == false && textEdit.onChange) textEdit.onChange(); + } + } + } + break; + } + + case WM_NOTIFY: { + unsigned id = LOWORD(wparam); + HWND control = GetDlgItem(window.p.hwnd, id); + if(control == 0) break; + Object *object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA); + if(object == 0) break; + if(dynamic_cast(object)) { + ListView &listView = (ListView&)*object; + LPNMHDR nmhdr = (LPNMHDR)lparam; + LPNMLISTVIEW nmlistview = (LPNMLISTVIEW)lparam; + + if(nmhdr->code == LVN_ITEMCHANGED && (nmlistview->uChanged & LVIF_STATE)) { + unsigned imagemask = ((nmlistview->uNewState & LVIS_STATEIMAGEMASK) >> 12) - 1; + if(imagemask == 0 || imagemask == 1) { + if(listView.p.locked == false && listView.onTick) listView.onTick(nmlistview->iItem); + } else if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) { + listView.p.lostFocus = true; + } else if(!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED)) { + listView.p.lostFocus = false; + listView.state.selected = true; + listView.state.selection = listView.selection(); + if(listView.p.locked == false && listView.onChange) listView.onChange(); + } else if(listView.p.lostFocus == false && listView.selected() == false) { + listView.p.lostFocus = false; + listView.state.selected = false; + listView.state.selection = 0; + if(listView.p.locked == false && listView.onChange) listView.onChange(); + } + } else if(nmhdr->code == LVN_ITEMACTIVATE) { + if(listView.onActivate) listView.onActivate(); + } + } + break; + } + + case WM_HSCROLL: + case WM_VSCROLL: { + Object *object = 0; + if(lparam) { + object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA); + } else { + unsigned id = LOWORD(wparam); + HWND control = GetDlgItem(window.p.hwnd, id); + if(control == 0) break; + object = (Object*)GetWindowLongPtr(control, GWLP_USERDATA); + } + if(object == 0) break; + + if(dynamic_cast(object) + || dynamic_cast(object)) { + SCROLLINFO info; + memset(&info, 0, sizeof(SCROLLINFO)); + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_ALL; + GetScrollInfo((HWND)lparam, SB_CTL, &info); + + switch(LOWORD(wparam)) { + case SB_LEFT: info.nPos = info.nMin; break; + case SB_RIGHT: info.nPos = info.nMax; break; + case SB_LINELEFT: info.nPos--; break; + case SB_LINERIGHT: info.nPos++; break; + case SB_PAGELEFT: info.nPos -= info.nMax >> 3; break; + case SB_PAGERIGHT: info.nPos += info.nMax >> 3; break; + case SB_THUMBTRACK: info.nPos = info.nTrackPos; break; + } + + info.fMask = SIF_POS; + SetScrollInfo((HWND)lparam, SB_CTL, &info, TRUE); + + //Windows may clamp position to scrollbar range + GetScrollInfo((HWND)lparam, SB_CTL, &info); + + if(dynamic_cast(object)) { + HorizontalScrollBar &horizontalScrollBar = (HorizontalScrollBar&)*object; + if(horizontalScrollBar.state.position != info.nPos) { + horizontalScrollBar.state.position = info.nPos; + if(horizontalScrollBar.onChange) horizontalScrollBar.onChange(); + } + } else { + VerticalScrollBar &verticalScrollBar = (VerticalScrollBar&)*object; + if(verticalScrollBar.state.position != info.nPos) { + verticalScrollBar.state.position = info.nPos; + if(verticalScrollBar.onChange) verticalScrollBar.onChange(); + } + } + + return TRUE; + } + + if(dynamic_cast(object)) { + HorizontalSlider &horizontalSlider = (HorizontalSlider&)*object; + if(horizontalSlider.state.position != horizontalSlider.position()) { + horizontalSlider.state.position = horizontalSlider.position(); + if(horizontalSlider.onChange) horizontalSlider.onChange(); + } + } else if(dynamic_cast(object)) { + VerticalSlider &verticalSlider = (VerticalSlider&)*object; + if(verticalSlider.state.position != verticalSlider.position()) { + verticalSlider.state.position = verticalSlider.position(); + if(verticalSlider.onChange) verticalSlider.onChange(); + } + } + + break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} diff --git a/phoenix/windows/platform.hpp b/phoenix/windows/platform.hpp new file mode 100755 index 00000000..2a132222 --- /dev/null +++ b/phoenix/windows/platform.hpp @@ -0,0 +1,433 @@ +struct pFont; +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static HFONT create(const string &description); + static void free(HFONT hfont); + static Geometry geometry(HFONT hfont, const string &text); +}; + +struct pObject { + Object &object; + uintptr_t id; + bool locked; + static array objects; + + pObject(Object &object); + static pObject* find(unsigned id); + virtual ~pObject() {} + + void constructor() {} + void destructor() {} +}; + +struct pOS : public pObject { + static Geometry availableGeometry(); + static Geometry desktopGeometry(); + static string fileLoad(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); +}; + +struct pTimer : public pObject { + Timer &timer; + UINT_PTR htimer; + + void setEnabled(bool enabled); + void setInterval(unsigned milliseconds); + + pTimer(Timer &timer) : pObject(timer), timer(timer) {} + void constructor(); +}; + +struct pMessageWindow : public pObject { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + +struct pWindow : public pObject { + Window &window; + HWND hwnd; + HMENU hmenu; + HWND hstatus; + HFONT hstatusfont; + HBRUSH brush; + COLORREF brushColor; + + void append(Layout &layout); + void append(Menu &menu); + void append(Widget &widget); + Color backgroundColor(); + bool focused(); + Geometry frameMargin(); + Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); + void setBackgroundColor(const Color &color); + void setFocused(); + void setFullScreen(bool fullScreen); + void setGeometry(const Geometry &geometry); + void setMenuFont(const string &font); + void setMenuVisible(bool visible); + void setResizable(bool resizable); + void setStatusFont(const string &font); + void setStatusText(const string &text); + void setStatusVisible(bool visible); + void setTitle(const string &text); + void setVisible(bool visible); + void setWidgetFont(const string &font); + + pWindow(Window &window) : pObject(window), window(window) {} + void constructor(); + void destructor(); + void updateMenu(); +}; + +struct pAction : public pObject { + Action &action; + Menu *parentMenu; + Window *parentWindow; + + void setEnabled(bool enabled); + void setVisible(bool visible); + + pAction(Action &action) : pObject(action), action(action) {} + void constructor(); +}; + +struct pMenu : public pAction { + Menu &menu; + HMENU hmenu; + + void append(Action &action); + void remove(Action &action); + void setText(const string &text); + + pMenu(Menu &menu) : pAction(menu), menu(menu) {} + void constructor(); + void destructor(); + void update(Window &parentWindow, Menu *parentMenu = 0); +}; + +struct pSeparator : public pAction { + Separator &separator; + + pSeparator(Separator &separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); +}; + +struct pItem : public pAction { + Item &item; + + void setText(const string &text); + + pItem(Item &item) : pAction(item), item(item) {} + void constructor(); + void destructor(); +}; + +struct pCheckItem : public pAction { + CheckItem &checkItem; + + bool checked(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} + void constructor(); + void destructor(); +}; + +struct pRadioItem : public pAction { + RadioItem &radioItem; + + bool checked(); + void setChecked(); + void setGroup(const reference_array &group); + void setText(const string &text); + + pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} + void constructor(); + void destructor(); +}; + +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { + Widget &widget; + Window *parentWindow; + HWND hwnd; + HFONT hfont; + + bool enabled(); + virtual Geometry minimumGeometry(); + void setEnabled(bool enabled); + void setFocused(); + void setFont(const string &font); + virtual void setGeometry(const Geometry &geometry); + void setVisible(bool visible); + + pWidget(Widget &widget) : pSizable(widget), widget(widget) { parentWindow = &Window::None; } + void constructor(); + void destructor(); + virtual void orphan(); + void setDefaultFont(); + void synchronize(); +}; + +struct pButton : public pWidget { + Button &button; + + Geometry minimumGeometry(); + void setText(const string &text); + + pButton(Button &button) : pWidget(button), button(button) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCanvas : public pWidget { + Canvas &canvas; + uint32_t *data; + + void setSize(const Size &size); + void update(); + + pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pCheckBox : public pWidget { + CheckBox &checkBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(bool checked); + void setText(const string &text); + + pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pComboBox : public pWidget { + ComboBox &comboBox; + + void append(const string &text); + Geometry minimumGeometry(); + void reset(); + unsigned selection(); + void setSelection(unsigned row); + + pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} + void constructor(); + void destructor(); + void orphan(); + void setGeometry(const Geometry &geometry); +}; + +struct pHexEdit : public pWidget { + HexEdit &hexEdit; + LRESULT CALLBACK (*windowProc)(HWND, UINT, LPARAM, WPARAM); + + void setColumns(unsigned columns); + void setLength(unsigned length); + void setOffset(unsigned offset); + void setRows(unsigned rows); + void update(); + + pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} + void constructor(); + void destructor(); + void orphan(); + bool keyPress(unsigned key); +}; + +struct pHorizontalScrollBar : public pWidget { + HorizontalScrollBar &horizontalScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pHorizontalSlider : public pWidget { + HorizontalSlider &horizontalSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLabel : public pWidget { + Label &label; + + Geometry minimumGeometry(); + void setText(const string &text); + + pLabel(Label &label) : pWidget(label), label(label) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pLineEdit : public pWidget { + LineEdit &lineEdit; + + Geometry minimumGeometry(); + void setEditable(bool editable); + void setText(const string &text); + string text(); + + pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pListView : public pWidget { + ListView &listView; + bool lostFocus; + + void append(const lstring &text); + void autoSizeColumns(); + bool checked(unsigned row); + void modify(unsigned row, const lstring &text); + void reset(); + bool selected(); + unsigned selection(); + void setCheckable(bool checkable); + void setChecked(unsigned row, bool checked); + void setHeaderText(const lstring &text); + void setHeaderVisible(bool visible); + void setSelected(bool selected); + void setSelection(unsigned row); + + pListView(ListView &listView) : pWidget(listView), listView(listView) {} + void constructor(); + void destructor(); + void orphan(); + void setGeometry(const Geometry &geometry); +}; + +struct pProgressBar : public pWidget { + ProgressBar &progressBar; + + Geometry minimumGeometry(); + void setPosition(unsigned position); + + pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pRadioBox : public pWidget { + RadioBox &radioBox; + + bool checked(); + Geometry minimumGeometry(); + void setChecked(); + void setGroup(const reference_array &group); + void setText(const string &text); + + pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pTextEdit : public pWidget { + TextEdit &textEdit; + + void setCursorPosition(unsigned position); + void setEditable(bool editable); + void setText(const string &text); + void setWordWrap(bool wordWrap); + string text(); + + pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pVerticalScrollBar : public pWidget { + VerticalScrollBar &verticalScrollBar; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pVerticalSlider : public pWidget { + VerticalSlider &verticalSlider; + + Geometry minimumGeometry(); + unsigned position(); + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); + void destructor(); + void orphan(); +}; + +struct pViewport : public pWidget { + Viewport &viewport; + + uintptr_t handle(); + + pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); + void destructor(); + void orphan(); +}; diff --git a/phoenix/windows/timer.cpp b/phoenix/windows/timer.cpp new file mode 100755 index 00000000..39e32a56 --- /dev/null +++ b/phoenix/windows/timer.cpp @@ -0,0 +1,31 @@ +static linear_vector timers; + +static void CALLBACK Timer_timeoutProc(HWND hwnd, UINT msg, UINT_PTR timerID, DWORD time) { + for(auto &timer : timers) { + if(timer->htimer == timerID) { + if(timer->timer.onTimeout) timer->timer.onTimeout(); + return; + } + } +} + +void pTimer::setEnabled(bool enabled) { + if(htimer) { + KillTimer(NULL, htimer); + htimer = 0; + } + + if(enabled == true) { + htimer = SetTimer(NULL, 0U, timer.state.milliseconds, Timer_timeoutProc); + } +} + +void pTimer::setInterval(unsigned milliseconds) { + //destroy and recreate timer if interval changed + setEnabled(timer.state.enabled); +} + +void pTimer::constructor() { + timers.append(this); + htimer = 0; +} diff --git a/phoenix/windows/widget/button.cpp b/phoenix/windows/widget/button.cpp new file mode 100755 index 00000000..9286f6e5 --- /dev/null +++ b/phoenix/windows/widget/button.cpp @@ -0,0 +1,25 @@ +Geometry pButton::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, button.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 10 }; +} + +void pButton::setText(const string &text) { + SetWindowText(hwnd, utf16_t(text)); +} + +void pButton::constructor() { + hwnd = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_TABSTOP, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&button); + setDefaultFont(); + setText(button.state.text); + synchronize(); +} + +void pButton::destructor() { + DestroyWindow(hwnd); +} + +void pButton::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/canvas.cpp b/phoenix/windows/widget/canvas.cpp new file mode 100755 index 00000000..232aea93 --- /dev/null +++ b/phoenix/windows/widget/canvas.cpp @@ -0,0 +1,62 @@ +static LRESULT CALLBACK Canvas_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + if(msg == WM_GETDLGCODE) { + return DLGC_STATIC | DLGC_WANTCHARS; + } + + if(msg == WM_PAINT) { + Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(object && dynamic_cast(object)) { + Canvas &canvas = (Canvas&)*object; + canvas.update(); + } + return TRUE; + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +void pCanvas::setSize(const Size &size) { + delete[] data; + data = new uint32_t[size.width * size.height]; + memcpy(data, canvas.state.data, size.width * size.height * sizeof(uint32_t)); +} + +void pCanvas::update() { + RECT rc; + GetClientRect(hwnd, &rc); + unsigned width = canvas.state.width, height = canvas.state.height; //rc.right, height = rc.bottom; + + BITMAPINFO bmi; + memset(&bmi, 0, sizeof(BITMAPINFO)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; //GDI stores bitmaps upside now; negative height flips bitmap + bmi.bmiHeader.biSizeImage = sizeof(uint32_t) * width * height; + + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + SetDIBitsToDevice(ps.hdc, 0, 0, width, height, 0, 0, 0, height, (void*)data, &bmi, DIB_RGB_COLORS); + EndPaint(hwnd, &ps); + InvalidateRect(hwnd, 0, false); +} + +void pCanvas::constructor() { + data = new uint32_t[canvas.state.width * canvas.state.height]; + memcpy(data, canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); + hwnd = CreateWindow(L"phoenix_canvas", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&canvas); + synchronize(); +} + +void pCanvas::destructor() { + DestroyWindow(hwnd); + delete[] data; +} + +void pCanvas::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/check-box.cpp b/phoenix/windows/widget/check-box.cpp new file mode 100755 index 00000000..8f0d2eb8 --- /dev/null +++ b/phoenix/windows/widget/check-box.cpp @@ -0,0 +1,39 @@ +bool pCheckBox::checked() { + return SendMessage(hwnd, BM_GETCHECK, 0, 0); +} + +Geometry pCheckBox::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, checkBox.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 4 }; +} + +void pCheckBox::setChecked(bool checked) { + SendMessage(hwnd, BM_SETCHECK, (WPARAM)checked, 0); +} + +void pCheckBox::setText(const string &text) { + SetWindowText(hwnd, utf16_t(text)); +} + +void pCheckBox::constructor() { + hwnd = CreateWindow( + L"BUTTON", L"", + WS_CHILD | WS_TABSTOP | BS_CHECKBOX, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&checkBox); + setDefaultFont(); + if(checkBox.state.checked) setChecked(true); + setText(checkBox.state.text); + synchronize(); + +} + +void pCheckBox::destructor() { + DestroyWindow(hwnd); +} + +void pCheckBox::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/combo-box.cpp b/phoenix/windows/widget/combo-box.cpp new file mode 100755 index 00000000..3e310a7b --- /dev/null +++ b/phoenix/windows/widget/combo-box.cpp @@ -0,0 +1,53 @@ +void pComboBox::append(const string &text) { + SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16_t(text)); + if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) setSelection(0); +} + +Geometry pComboBox::minimumGeometry() { + unsigned maximumWidth = 0; + for(auto &text : comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(hfont, text).width); + return { 0, 0, maximumWidth + 24, pFont::geometry(hfont, " ").height + 10 }; +} + +void pComboBox::reset() { + SendMessage(hwnd, CB_RESETCONTENT, 0, 0); +} + +unsigned pComboBox::selection() { + return SendMessage(hwnd, CB_GETCURSEL, 0, 0); +} + +void pComboBox::setSelection(unsigned row) { + SendMessage(hwnd, CB_SETCURSEL, row, 0); +} + +void pComboBox::constructor() { + hwnd = CreateWindow( + L"COMBOBOX", L"", + WS_CHILD | WS_TABSTOP | CBS_DROPDOWNLIST | CBS_HASSTRINGS, + 0, 0, 0, 0, + parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&comboBox); + setDefaultFont(); + for(auto &text : comboBox.state.text) append(text); + setSelection(comboBox.state.selection); + synchronize(); +} + +void pComboBox::destructor() { + DestroyWindow(hwnd); +} + +void pComboBox::orphan() { + destructor(); + constructor(); +} + +void pComboBox::setGeometry(const Geometry &geometry) { + SetWindowPos(hwnd, NULL, geometry.x, geometry.y, geometry.width, 1, SWP_NOZORDER); + RECT rc; + GetWindowRect(hwnd, &rc); + unsigned adjustedHeight = geometry.height - ((rc.bottom - rc.top) - SendMessage(hwnd, CB_GETITEMHEIGHT, (WPARAM)-1, 0)); + SendMessage(hwnd, CB_SETITEMHEIGHT, (WPARAM)-1, adjustedHeight); +} diff --git a/phoenix/windows/widget/hex-edit.cpp b/phoenix/windows/widget/hex-edit.cpp new file mode 100755 index 00000000..789f4faf --- /dev/null +++ b/phoenix/windows/widget/hex-edit.cpp @@ -0,0 +1,136 @@ +static LRESULT CALLBACK HexEdit_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + HexEdit &hexEdit = *(HexEdit*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(msg == WM_CHAR) { + if(hexEdit.p.keyPress(wparam)) return 0; + } + return hexEdit.p.windowProc(hwnd, msg, wparam, lparam); +} + +void pHexEdit::setColumns(unsigned columns) { + update(); +} + +void pHexEdit::setLength(unsigned length) { + update(); +} + +void pHexEdit::setOffset(unsigned offset) { + update(); +} + +void pHexEdit::setRows(unsigned rows) { + update(); +} + +void pHexEdit::update() { + if(!hexEdit.onRead) { + SetWindowText(hwnd, L""); + return; + } + + unsigned cursorPosition = Edit_GetSel(hwnd); + + string output; + unsigned offset = hexEdit.state.offset; + for(unsigned row = 0; row < hexEdit.state.rows; row++) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(unsigned column = 0; column < hexEdit.state.columns; column++) { + if(offset < hexEdit.state.length) { + uint8_t data = hexEdit.onRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 }; + ansidata.append(buffer); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= hexEdit.state.length) break; + if(row != hexEdit.state.rows - 1) output.append("\r\n"); + } + + SetWindowText(hwnd, utf16_t(output)); + Edit_SetSel(hwnd, LOWORD(cursorPosition), HIWORD(cursorPosition)); +} + +void pHexEdit::constructor() { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&hexEdit); + setDefaultFont(); + update(); + + windowProc = (LRESULT CALLBACK (*)(HWND, UINT, LPARAM, WPARAM))GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HexEdit_windowProc); + synchronize(); +} + +void pHexEdit::destructor() { + DestroyWindow(hwnd); +} + +void pHexEdit::orphan() { + destructor(); + constructor(); +} + +bool pHexEdit::keyPress(unsigned scancode) { + if(!hexEdit.onRead) return false; + + unsigned position = LOWORD(Edit_GetSel(hwnd)); + unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 2; + unsigned cursorY = position / lineWidth; + unsigned cursorX = position % lineWidth; + + //convert scancode to hex nibble + if(scancode >= '0' && scancode <= '9') scancode = scancode - '0'; + else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10; + else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10; + else return false; + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < hexEdit.state.columns) { + //not in ANSI region + unsigned offset = hexEdit.state.offset + (cursorY * hexEdit.state.columns + cursorX); + + if(offset >= hexEdit.state.length) return false; //do not edit past end of data + uint8_t data = hexEdit.onRead(offset); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (scancode << 0); + } else { + data = (data & 0x0f) | (scancode << 4); + } + if(hexEdit.onWrite) hexEdit.onWrite(offset, data); + + //auto-advance cursor to next nibble or byte + position++; + if(cursorNibble && cursorX != hexEdit.state.columns - 1) position++; + Edit_SetSel(hwnd, position, position); + + //refresh output to reflect modified data + update(); + } + } + } + + return true; +} diff --git a/phoenix/windows/widget/horizontal-scroll-bar.cpp b/phoenix/windows/widget/horizontal-scroll-bar.cpp new file mode 100755 index 00000000..250ac247 --- /dev/null +++ b/phoenix/windows/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,38 @@ +Geometry pHorizontalScrollBar::minimumGeometry() { + return { 0, 0, 0, 18 }; +} + +unsigned pHorizontalScrollBar::position() { + return GetScrollPos(hwnd, SB_CTL); +} + +void pHorizontalScrollBar::setLength(unsigned length) { + length += (length == 0); + SetScrollRange(hwnd, SB_CTL, 0, length - 1, TRUE); + horizontalScrollBar.setPosition(0); +} + +void pHorizontalScrollBar::setPosition(unsigned position) { + SetScrollPos(hwnd, SB_CTL, position, TRUE); +} + +void pHorizontalScrollBar::constructor() { + hwnd = CreateWindow( + L"SCROLLBAR", L"", WS_CHILD | WS_TABSTOP | SBS_HORZ, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&horizontalScrollBar); + unsigned position = horizontalScrollBar.state.position; + setLength(horizontalScrollBar.state.length); + horizontalScrollBar.setPosition(position); + synchronize(); +} + +void pHorizontalScrollBar::destructor() { + DestroyWindow(hwnd); +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/horizontal-slider.cpp b/phoenix/windows/widget/horizontal-slider.cpp new file mode 100755 index 00000000..807086ae --- /dev/null +++ b/phoenix/windows/widget/horizontal-slider.cpp @@ -0,0 +1,39 @@ +Geometry pHorizontalSlider::minimumGeometry() { + return { 0, 0, 0, 25 }; +} + +unsigned pHorizontalSlider::position() { + return SendMessage(hwnd, TBM_GETPOS, 0, 0); +} + +void pHorizontalSlider::setLength(unsigned length) { + length += (length == 0); + SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1)); + SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3)); + horizontalSlider.setPosition(0); +} + +void pHorizontalSlider::setPosition(unsigned position) { + SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)position); +} + +void pHorizontalSlider::constructor() { + hwnd = CreateWindow( + TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_HORZ, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&horizontalSlider); + unsigned position = horizontalSlider.state.position; + setLength(horizontalSlider.state.length); + horizontalSlider.setPosition(position); + synchronize(); +} + +void pHorizontalSlider::destructor() { + DestroyWindow(hwnd); +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/label.cpp b/phoenix/windows/widget/label.cpp new file mode 100755 index 00000000..56f0d433 --- /dev/null +++ b/phoenix/windows/widget/label.cpp @@ -0,0 +1,64 @@ +Geometry pLabel::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, label.state.text); + return { 0, 0, geometry.width, geometry.height }; +} + +void pLabel::setText(const string &text) { + SetWindowText(hwnd, utf16_t(text)); + InvalidateRect(hwnd, 0, false); +} + +void pLabel::constructor() { + hwnd = CreateWindow(L"phoenix_label", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&label); + setDefaultFont(); + setText(label.state.text); + synchronize(); +} + +void pLabel::destructor() { + DestroyWindow(hwnd); +} + +void pLabel::orphan() { + destructor(); + constructor(); +} + +static LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + Window *window = (Window*)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA); + Label *label = (Label*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!window || !label) return DefWindowProc(hwnd, msg, wparam, lparam); + + if(msg == WM_GETDLGCODE) { + return DLGC_STATIC | DLGC_WANTCHARS; + } + + if(msg == WM_ERASEBKGND) { + //background is erased during WM_PAINT to prevent flickering + return TRUE; + } + + if(msg == WM_PAINT) { + PAINTSTRUCT ps; + RECT rc; + BeginPaint(hwnd, &ps); + GetClientRect(hwnd, &rc); + FillRect(ps.hdc, &rc, window->p.brush ? window->p.brush : GetSysColorBrush(COLOR_3DFACE)); + SetBkColor(ps.hdc, window->p.brush ? window->p.brushColor : GetSysColor(COLOR_3DFACE)); + SelectObject(ps.hdc, ((Widget*)label)->p.hfont); + unsigned length = GetWindowTextLength(hwnd); + wchar_t text[length + 1]; + GetWindowText(hwnd, text, length + 1); + text[length] = 0; + DrawText(ps.hdc, text, -1, &rc, DT_CALCRECT | DT_END_ELLIPSIS); + unsigned height = rc.bottom; + GetClientRect(hwnd, &rc); + rc.top = (rc.bottom - height) / 2; + rc.bottom = rc.top + height; + DrawText(ps.hdc, text, -1, &rc, DT_LEFT | DT_END_ELLIPSIS); + EndPaint(hwnd, &ps); + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} diff --git a/phoenix/windows/widget/line-edit.cpp b/phoenix/windows/widget/line-edit.cpp new file mode 100755 index 00000000..eb6a8fb7 --- /dev/null +++ b/phoenix/windows/widget/line-edit.cpp @@ -0,0 +1,45 @@ +Geometry pLineEdit::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, lineEdit.state.text); + return { 0, 0, geometry.width + 12, geometry.height + 10 }; +} + +void pLineEdit::setEditable(bool editable) { + SendMessage(hwnd, EM_SETREADONLY, editable == false, 0); +} + +void pLineEdit::setText(const string &text) { + locked = true; + SetWindowText(hwnd, utf16_t(text)); + locked = false; +} + +string pLineEdit::text() { + unsigned length = GetWindowTextLength(hwnd); + wchar_t text[length + 1]; + GetWindowText(hwnd, text, length + 1); + text[length] = 0; + return (const char*)utf8_t(text); +} + +void pLineEdit::constructor() { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&lineEdit); + setDefaultFont(); + setEditable(lineEdit.state.editable); + setText(lineEdit.state.text); + synchronize(); +} + +void pLineEdit::destructor() { + lineEdit.state.text = text(); + DestroyWindow(hwnd); +} + +void pLineEdit::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/list-view.cpp b/phoenix/windows/widget/list-view.cpp new file mode 100755 index 00000000..efa66f6b --- /dev/null +++ b/phoenix/windows/widget/list-view.cpp @@ -0,0 +1,140 @@ +void pListView::append(const lstring &list) { + wchar_t empty[] = L""; + unsigned row = ListView_GetItemCount(hwnd); + LVITEM item; + item.mask = LVIF_TEXT; + item.iItem = row; + item.iSubItem = 0; + item.pszText = empty; + locked = true; + ListView_InsertItem(hwnd, &item); + locked = false; + for(unsigned n = 0; n < list.size(); n++) { + utf16_t wtext(list[n]); + ListView_SetItemText(hwnd, row, n, wtext); + } +} + +void pListView::autoSizeColumns() { + for(unsigned n = 0; n < max(1, listView.state.headerText.size()); n++) { + ListView_SetColumnWidth(hwnd, n, LVSCW_AUTOSIZE_USEHEADER); + } +} + +bool pListView::checked(unsigned row) { + return ListView_GetCheckState(hwnd, row); +} + +void pListView::modify(unsigned row, const lstring &list) { + for(unsigned n = 0; n < list.size(); n++) { + utf16_t wtext(list[n]); + ListView_SetItemText(hwnd, row, n, wtext); + } +} + +void pListView::reset() { + ListView_DeleteAllItems(hwnd); +} + +bool pListView::selected() { + unsigned count = ListView_GetItemCount(hwnd); + for(unsigned n = 0; n < count; n++) { + if(ListView_GetItemState(hwnd, n, LVIS_SELECTED)) return true; + } + return false; +} + +unsigned pListView::selection() { + unsigned count = ListView_GetItemCount(hwnd); + for(unsigned n = 0; n < count; n++) { + if(ListView_GetItemState(hwnd, n, LVIS_SELECTED)) return n; + } + return listView.state.selection; +} + +void pListView::setCheckable(bool checkable) { + ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT | (checkable ? LVS_EX_CHECKBOXES : 0)); +} + +void pListView::setChecked(unsigned row, bool checked) { + locked = true; + ListView_SetCheckState(hwnd, row, checked); + locked = false; +} + +void pListView::setHeaderText(const lstring &list) { + while(ListView_DeleteColumn(hwnd, 0)); + + lstring headers = list; + if(headers.size() == 0) headers.append(""); //must have at least one column + + for(unsigned n = 0; n < headers.size(); n++) { + LVCOLUMN column; + column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM; + column.fmt = LVCFMT_LEFT; + column.iSubItem = n; + utf16_t headerText(headers[n]); + column.pszText = headerText; + ListView_InsertColumn(hwnd, n, &column); + } + autoSizeColumns(); +} + +void pListView::setHeaderVisible(bool visible) { + SetWindowLong( + hwnd, GWL_STYLE, + (GetWindowLong(hwnd, GWL_STYLE) & ~LVS_NOCOLUMNHEADER) | + (visible ? 0 : LVS_NOCOLUMNHEADER) + ); +} + +void pListView::setSelected(bool selected) { + locked = true; + lostFocus = false; + if(selected == false) { + ListView_SetItemState(hwnd, -1, 0, LVIS_FOCUSED | LVIS_SELECTED); + } else { + setSelection(listView.state.selection); + } + locked = false; +} + +void pListView::setSelection(unsigned row) { + locked = true; + lostFocus = false; + ListView_SetItemState(hwnd, row, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); + locked = false; +} + +void pListView::constructor() { + lostFocus = false; + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, WC_LISTVIEW, L"", + WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | LVS_NOCOLUMNHEADER, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&listView); + setDefaultFont(); + setHeaderText(listView.state.headerText); + setHeaderVisible(listView.state.headerVisible); + setCheckable(listView.state.checkable); + for(auto &text : listView.state.text) append(text); + for(unsigned n = 0; n < listView.state.checked.size(); n++) setChecked(n, listView.state.checked[n]); + if(listView.state.selected) setSelection(listView.state.selection); + autoSizeColumns(); + synchronize(); +} + +void pListView::destructor() { + DestroyWindow(hwnd); +} + +void pListView::orphan() { + destructor(); + constructor(); +} + +void pListView::setGeometry(const Geometry &geometry) { + pWidget::setGeometry(geometry); + autoSizeColumns(); +} diff --git a/phoenix/windows/widget/progress-bar.cpp b/phoenix/windows/widget/progress-bar.cpp new file mode 100755 index 00000000..f4703f1e --- /dev/null +++ b/phoenix/windows/widget/progress-bar.cpp @@ -0,0 +1,25 @@ +Geometry pProgressBar::minimumGeometry() { + return { 0, 0, 0, 23 }; +} + +void pProgressBar::setPosition(unsigned position) { + SendMessage(hwnd, PBM_SETPOS, (WPARAM)position, 0); +} + +void pProgressBar::constructor() { + hwnd = CreateWindow(PROGRESS_CLASS, L"", WS_CHILD | PBS_SMOOTH, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&progressBar); + SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + SendMessage(hwnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0); + setPosition(progressBar.state.position); + synchronize(); +} + +void pProgressBar::destructor() { + DestroyWindow(hwnd); +} + +void pProgressBar::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/radio-box.cpp b/phoenix/windows/widget/radio-box.cpp new file mode 100755 index 00000000..555a27a8 --- /dev/null +++ b/phoenix/windows/widget/radio-box.cpp @@ -0,0 +1,43 @@ +bool pRadioBox::checked() { + return SendMessage(hwnd, BM_GETCHECK, 0, 0); +} + +Geometry pRadioBox::minimumGeometry() { + Geometry geometry = pFont::geometry(hfont, radioBox.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 4 }; +} + +void pRadioBox::setChecked() { + for(auto &item : radioBox.state.group) { + SendMessage(item.p.hwnd, BM_SETCHECK, (WPARAM)(&item == &radioBox), 0); + } +} + +void pRadioBox::setGroup(const reference_array &group) { +} + +void pRadioBox::setText(const string &text) { + SetWindowText(hwnd, utf16_t(text)); +} + +void pRadioBox::constructor() { + hwnd = CreateWindow( + L"BUTTON", L"", + WS_CHILD | WS_TABSTOP | BS_RADIOBUTTON, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&radioBox); + setDefaultFont(); + if(radioBox.state.checked) setChecked(); + setText(radioBox.state.text); + synchronize(); +} + +void pRadioBox::destructor() { + DestroyWindow(hwnd); +} + +void pRadioBox::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/text-edit.cpp b/phoenix/windows/widget/text-edit.cpp new file mode 100755 index 00000000..c341156c --- /dev/null +++ b/phoenix/windows/widget/text-edit.cpp @@ -0,0 +1,56 @@ +void pTextEdit::setCursorPosition(unsigned position) { + Edit_SetSel(hwnd, position, position); +} + +void pTextEdit::setEditable(bool editable) { + SendMessage(hwnd, EM_SETREADONLY, editable == false, (LPARAM)0); +} + +void pTextEdit::setText(const string &text) { + locked = true; + string output = text; + output.replace("\r", ""); + output.replace("\n", "\r\n"); + SetWindowText(hwnd, utf16_t(output)); + locked = false; +} + +void pTextEdit::setWordWrap(bool wordWrap) { + //ES_AUTOHSCROLL cannot be changed after widget creation. + //As a result, we must destroy and re-create widget to change this setting. + orphan(); +} + +string pTextEdit::text() { + unsigned length = GetWindowTextLength(hwnd); + wchar_t buffer[length + 1]; + GetWindowText(hwnd, buffer, length + 1); + buffer[length] = 0; + string text = (const char*)utf8_t(buffer); + text.replace("\r", ""); + return text; +} + +void pTextEdit::constructor() { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | (textEdit.state.wordWrap == false ? ES_AUTOHSCROLL : 0), + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&textEdit); + setDefaultFont(); + setCursorPosition(textEdit.state.cursorPosition); + setEditable(textEdit.state.editable); + setText(textEdit.state.text); + synchronize(); +} + +void pTextEdit::destructor() { + textEdit.state.text = text(); + DestroyWindow(hwnd); +} + +void pTextEdit::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/vertical-scroll-bar.cpp b/phoenix/windows/widget/vertical-scroll-bar.cpp new file mode 100755 index 00000000..dcc281f2 --- /dev/null +++ b/phoenix/windows/widget/vertical-scroll-bar.cpp @@ -0,0 +1,38 @@ +Geometry pVerticalScrollBar::minimumGeometry() { + return { 0, 0, 18, 0 }; +} + +unsigned pVerticalScrollBar::position() { + return GetScrollPos(hwnd, SB_CTL); +} + +void pVerticalScrollBar::setLength(unsigned length) { + length += (length == 0); + SetScrollRange(hwnd, SB_CTL, 0, length - 1, TRUE); + verticalScrollBar.setPosition(0); +} + +void pVerticalScrollBar::setPosition(unsigned position) { + SetScrollPos(hwnd, SB_CTL, position, TRUE); +} + +void pVerticalScrollBar::constructor() { + hwnd = CreateWindow( + L"SCROLLBAR", L"", WS_CHILD | SBS_VERT, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&verticalScrollBar); + unsigned position = verticalScrollBar.state.position; + setLength(verticalScrollBar.state.length); + verticalScrollBar.setPosition(position); + synchronize(); +} + +void pVerticalScrollBar::destructor() { + DestroyWindow(hwnd); +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/vertical-slider.cpp b/phoenix/windows/widget/vertical-slider.cpp new file mode 100755 index 00000000..ac5cb1ce --- /dev/null +++ b/phoenix/windows/widget/vertical-slider.cpp @@ -0,0 +1,39 @@ +Geometry pVerticalSlider::minimumGeometry() { + return { 0, 0, 0, 25 }; +} + +unsigned pVerticalSlider::position() { + return SendMessage(hwnd, TBM_GETPOS, 0, 0); +} + +void pVerticalSlider::setLength(unsigned length) { + length += (length == 0); + SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1)); + SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3)); + verticalSlider.setPosition(0); +} + +void pVerticalSlider::setPosition(unsigned position) { + SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)position); +} + +void pVerticalSlider::constructor() { + hwnd = CreateWindow( + TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_VERT, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&verticalSlider); + unsigned position = verticalSlider.state.position; + setLength(verticalSlider.state.length); + verticalSlider.setPosition(position); + synchronize(); +} + +void pVerticalSlider::destructor() { + DestroyWindow(hwnd); +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); +} diff --git a/phoenix/windows/widget/viewport.cpp b/phoenix/windows/widget/viewport.cpp new file mode 100755 index 00000000..e46764f7 --- /dev/null +++ b/phoenix/windows/widget/viewport.cpp @@ -0,0 +1,23 @@ +uintptr_t pViewport::handle() { + return (uintptr_t)hwnd; +} + +void pViewport::constructor() { + hwnd = CreateWindow(L"phoenix_viewport", L"", WS_CHILD | WS_DISABLED, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&viewport); + synchronize(); +} + +void pViewport::destructor() { + DestroyWindow(hwnd); +} + +void pViewport::orphan() { + destructor(); + constructor(); +} + +static LRESULT CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + if(msg == WM_GETDLGCODE) return DLGC_STATIC | DLGC_WANTCHARS; + return DefWindowProc(hwnd, msg, wparam, lparam); +} diff --git a/phoenix/windows/widget/widget.cpp b/phoenix/windows/widget/widget.cpp new file mode 100755 index 00000000..b0e60c7d --- /dev/null +++ b/phoenix/windows/widget/widget.cpp @@ -0,0 +1,66 @@ +bool pWidget::enabled() { + return IsWindowEnabled(hwnd); +} + +Geometry pWidget::minimumGeometry() { + return { 0, 0, 0, 0 }; +} + +void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; + EnableWindow(hwnd, enabled); +} + +void pWidget::setFocused() { + SetFocus(hwnd); +} + +void pWidget::setFont(const string &font) { + if(hfont) DeleteObject(hfont); + hfont = pFont::create(font); + SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); +} + +void pWidget::setGeometry(const Geometry &geometry) { + SetWindowPos(hwnd, NULL, geometry.x, geometry.y, geometry.width, geometry.height, SWP_NOZORDER); +} + +void pWidget::setVisible(bool visible) { + if(widget.state.abstract) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; + ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); +} + +void pWidget::constructor() { + hfont = pFont::create("Tahoma, 8"); + if(widget.state.abstract) { + hwnd = CreateWindow(L"phoenix_label", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&widget); + } +} + +void pWidget::destructor() { + if(widget.state.abstract) { + DestroyWindow(hwnd); + } +} + +void pWidget::orphan() { + destructor(); + constructor(); +} + +void pWidget::setDefaultFont() { + string description = widget.state.font; + if(description == "") description = "Tahoma, 8"; + hfont = pFont::create(description); + SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); +} + +//calling Widget::setParent destroys widget and re-creates it: +//need to re-apply visiblity and enabled status; called by each subclassed setParent() function +void pWidget::synchronize() { + widget.setEnabled(widget.enabled()); + widget.setVisible(widget.visible()); +} diff --git a/phoenix/windows/window.cpp b/phoenix/windows/window.cpp new file mode 100755 index 00000000..4319d7c4 --- /dev/null +++ b/phoenix/windows/window.cpp @@ -0,0 +1,202 @@ +static const unsigned FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER; +static const unsigned ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME; + +void pWindow::append(Layout &layout) { + Geometry geom = window.state.geometry; + geom.x = geom.y = 0; + layout.setGeometry(geom); +} + +void pWindow::append(Menu &menu) { + menu.p.parentWindow = &window; + updateMenu(); +} + +void pWindow::append(Widget &widget) { + widget.p.parentWindow = &window; + widget.p.orphan(); + if(widget.state.font != "") widget.p.setFont(widget.state.font); + else if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Tahoma, 8"); +} + +Color pWindow::backgroundColor() { + if(window.state.backgroundColorOverride) return window.state.backgroundColor; + DWORD color = GetSysColor(COLOR_3DFACE); + return { (uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color >> 0), 255 }; +} + +bool pWindow::focused() { + return (GetForegroundWindow() == hwnd); +} + +Geometry pWindow::frameMargin() { + unsigned style = window.state.resizable ? ResizableStyle : FixedStyle; + if(window.state.fullScreen) style = 0; + RECT rc = { 0, 0, 640, 480 }; + AdjustWindowRect(&rc, style, window.state.menuVisible); + unsigned statusHeight = 0; + if(window.state.statusVisible) { + RECT src; + GetClientRect(hstatus, &src); + statusHeight = src.bottom - src.top; + } + return { abs(rc.left), abs(rc.top), (rc.right - rc.left) - 640, (rc.bottom - rc.top) + statusHeight - 480 }; +} + +Geometry pWindow::geometry() { + Geometry margin = frameMargin(); + + RECT rc; + if(IsIconic(hwnd)) { + //GetWindowRect returns -32000(x),-32000(y) when window is minimized + WINDOWPLACEMENT wp; + GetWindowPlacement(hwnd, &wp); + rc = wp.rcNormalPosition; + } else { + GetWindowRect(hwnd, &rc); + } + + signed x = rc.left + margin.x; + signed y = rc.top + margin.y; + unsigned width = (rc.right - rc.left) - margin.width; + unsigned height = (rc.bottom - rc.top) - margin.height; + + return { x, y, width, height }; +} + +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + updateMenu(); +} + +void pWindow::remove(Widget &widget) { + widget.p.orphan(); +} + +void pWindow::setBackgroundColor(const Color &color) { + if(brush) DeleteObject(brush); + brushColor = RGB(color.red, color.green, color.blue); + brush = CreateSolidBrush(brushColor); +} + +void pWindow::setFocused() { + if(window.state.visible == false) setVisible(true); + SetFocus(hwnd); +} + +void pWindow::setFullScreen(bool fullScreen) { + locked = true; + if(fullScreen == false) { + SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | (window.state.resizable ? ResizableStyle : FixedStyle)); + setGeometry(window.state.geometry); + } else { + SetWindowLongPtr(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP); + Geometry margin = frameMargin(); + setGeometry({ margin.x, margin.y, GetSystemMetrics(SM_CXSCREEN) - margin.width, GetSystemMetrics(SM_CYSCREEN) - margin.height }); + } + locked = false; +} + +void pWindow::setGeometry(const Geometry &geometry) { + locked = true; + Geometry margin = frameMargin(); + SetWindowPos( + hwnd, NULL, + geometry.x - margin.x, geometry.y - margin.y, + geometry.width + margin.width, geometry.height + margin.height, + SWP_NOZORDER | SWP_FRAMECHANGED + ); + SetWindowPos(hstatus, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED); + for(auto &layout : window.state.layout) { + Geometry geom = this->geometry(); + geom.x = geom.y = 0; + layout.setGeometry(geom); + } + locked = false; +} + +void pWindow::setMenuFont(const string &font) { +} + +void pWindow::setMenuVisible(bool visible) { + locked = true; + SetMenu(hwnd, visible ? hmenu : 0); + setGeometry(window.state.geometry); + locked = false; +} + +void pWindow::setResizable(bool resizable) { + SetWindowLongPtr(hwnd, GWL_STYLE, window.state.resizable ? ResizableStyle : FixedStyle); + setGeometry(window.state.geometry); +} + +void pWindow::setStatusFont(const string &font) { + if(hstatusfont) DeleteObject(hstatusfont); + hstatusfont = pFont::create(font); + SendMessage(hstatus, WM_SETFONT, (WPARAM)hstatusfont, 0); +} + +void pWindow::setStatusText(const string &text) { + SendMessage(hstatus, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text)); +} + +void pWindow::setStatusVisible(bool visible) { + locked = true; + ShowWindow(hstatus, visible ? SW_SHOWNORMAL : SW_HIDE); + setGeometry(window.state.geometry); + locked = false; +} + +void pWindow::setTitle(const string &text) { + SetWindowText(hwnd, utf16_t(text)); +} + +void pWindow::setVisible(bool visible) { + ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); +} + +void pWindow::setWidgetFont(const string &font) { + for(auto &widget : window.state.widget) { + if(widget.state.font == "") widget.setFont(font); + } +} + +void pWindow::constructor() { + brush = 0; + + hwnd = CreateWindow(L"phoenix_window", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0); + hmenu = CreateMenu(); + hstatus = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD, 0, 0, 0, 0, hwnd, 0, GetModuleHandle(0), 0); + hstatusfont = 0; + setStatusFont("Tahoma, 8"); + + //status bar will be capable of receiving tab focus if it is not disabled + SetWindowLongPtr(hstatus, GWL_STYLE, GetWindowLong(hstatus, GWL_STYLE) | WS_DISABLED); + + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&window); + setGeometry({ 128, 128, 256, 256 }); +} + +void pWindow::destructor() { + DeleteObject(hstatusfont); + DestroyWindow(hstatus); + DestroyMenu(hmenu); + DestroyWindow(hwnd); +} + +void pWindow::updateMenu() { + if(hmenu) DestroyMenu(hmenu); + hmenu = CreateMenu(); + + for(auto &menu : window.state.menu) { + menu.p.update(window); + if(menu.visible()) { + AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)menu.p.hmenu, utf16_t(menu.state.text)); + } + } + + SetMenu(hwnd, window.state.menuVisible ? hmenu : 0); +} diff --git a/ruby/Makefile b/ruby/Makefile new file mode 100755 index 00000000..1231bcd5 --- /dev/null +++ b/ruby/Makefile @@ -0,0 +1,26 @@ +rubyflags := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c) +rubyflags += $(if $(finstring .sdl,$(ruby)),`sdl-config --cflags`) + +rubylink := +rubylink += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`) +rubylink += $(if $(findstring video.direct3d,$(ruby)),-ld3d9) +rubylink += $(if $(findstring video.directdraw,$(ruby)),-lddraw) +rubylink += $(if $(findstring video.glx,$(ruby)),-lGL) +rubylink += $(if $(findstring video.wgl,$(ruby)),-lopengl32) +rubylink += $(if $(findstring video.xv,$(ruby)),-lXv) +rubylink += $(if $(findstring audio.alsa,$(ruby)),-lasound) +rubylink += $(if $(findstring audio.ao,$(ruby)),-lao) +rubylink += $(if $(findstring audio.directsound,$(ruby)),-ldsound) +rubylink += $(if $(findstring audio.pulseaudio,$(ruby)),-lpulse) +rubylink += $(if $(findstring audio.pulseaudiosimple,$(ruby)),-lpulse-simple) +rubylink += $(if $(findstring audio.xaudio2,$(ruby)),-lole32) +rubylink += $(if $(findstring input.directinput,$(ruby)),-ldinput8 -ldxguid) +rubylink += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid) + +ifeq ($(platform),x) +rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal) +else ifeq ($(platform),osx) +rubylink += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL) +else ifeq ($(platform),win) +rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal32) +endif diff --git a/ruby/audio.hpp b/ruby/audio.hpp new file mode 100755 index 00000000..45ae96ef --- /dev/null +++ b/ruby/audio.hpp @@ -0,0 +1,19 @@ +class Audio { +public: + static const char *Handle; + static const char *Synchronize; + static const char *Frequency; + static const char *Latency; + + virtual bool cap(const nall::string& name) { return false; } + virtual nall::any get(const nall::string& name) { return false; } + virtual bool set(const nall::string& name, const nall::any& value) { return false; } + + virtual void sample(uint16_t left, uint16_t right) {} + virtual void clear() {} + virtual bool init() { return true; } + virtual void term() {} + + Audio() {} + virtual ~Audio() {} +}; diff --git a/ruby/audio/alsa.cpp b/ruby/audio/alsa.cpp new file mode 100755 index 00000000..45b4a8bd --- /dev/null +++ b/ruby/audio/alsa.cpp @@ -0,0 +1,240 @@ +//audio.alsa (2009-11-30) +//authors: BearOso, byuu, Nach, RedDwarf + +#include + +namespace ruby { + +class pAudioALSA { +public: + struct { + snd_pcm_t *handle; + snd_pcm_format_t format; + snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t period_size; + int channels; + const char *name; + } device; + + struct { + uint32_t *data; + unsigned length; + } buffer; + + struct { + bool synchronize; + unsigned frequency; + unsigned latency; + } settings; + + bool cap(const string& name) { + if(name == Audio::Synchronize) return true; + if(name == Audio::Frequency) return true; + if(name == Audio::Latency) return true; + return false; + } + + any get(const string& name) { + if(name == Audio::Synchronize) return settings.synchronize; + if(name == Audio::Frequency) return settings.frequency; + if(name == Audio::Latency) return settings.latency; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Audio::Synchronize) { + if(settings.synchronize != any_cast(value)) { + settings.synchronize = any_cast(value); + if(device.handle) init(); + } + return true; + } + + if(name == Audio::Frequency) { + if(settings.frequency != any_cast(value)) { + settings.frequency = any_cast(value); + if(device.handle) init(); + } + return true; + } + + if(name == Audio::Latency) { + if(settings.latency != any_cast(value)) { + settings.latency = any_cast(value); + if(device.handle) init(); + } + return true; + } + + return false; + } + + void sample(uint16_t left, uint16_t right) { + if(!device.handle) return; + + buffer.data[buffer.length++] = left + (right << 16); + if(buffer.length < device.period_size) return; + + snd_pcm_sframes_t avail; + do { + avail = snd_pcm_avail_update(device.handle); + if(avail < 0) snd_pcm_recover(device.handle, avail, 1); + if(avail < buffer.length) { + if(settings.synchronize == false) { + buffer.length = 0; + return; + } + int error = snd_pcm_wait(device.handle, -1); + if(error < 0) snd_pcm_recover(device.handle, error, 1); + } + } while(avail < buffer.length); + + //below code has issues with PulseAudio sound server + #if 0 + if(settings.synchronize == false) { + snd_pcm_sframes_t avail = snd_pcm_avail_update(device.handle); + if(avail < device.period_size) { + buffer.length = 0; + return; + } + } + #endif + + uint32_t *buffer_ptr = buffer.data; + int i = 4; + + while((buffer.length > 0) && i--) { + snd_pcm_sframes_t written = snd_pcm_writei(device.handle, buffer_ptr, buffer.length); + if(written < 0) { + //no samples written + snd_pcm_recover(device.handle, written, 1); + } else if(written <= buffer.length) { + buffer.length -= written; + buffer_ptr += written; + } + } + + if(i < 0) { + if(buffer.data == buffer_ptr) { + buffer.length--; + buffer_ptr++; + } + memmove(buffer.data, buffer_ptr, buffer.length * sizeof(uint32_t)); + } + } + + void clear() { + } + + bool init() { + term(); + + if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { + term(); + return false; + } + + //below code will not work with 24khz frequency rate (ALSA library bug) + #if 0 + if(snd_pcm_set_params(device.handle, device.format, SND_PCM_ACCESS_RW_INTERLEAVED, + device.channels, settings.frequency, 1, settings.latency * 1000) < 0) { + //failed to set device parameters + term(); + return false; + } + + if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) { + device.period_size = settings.latency * 1000 * 1e-6 * settings.frequency / 4; + } + #endif + + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + unsigned rate = settings.frequency; + unsigned buffer_time = settings.latency * 1000; + unsigned period_time = settings.latency * 1000 / 4; + + snd_pcm_hw_params_alloca(&hwparams); + if(snd_pcm_hw_params_any(device.handle, hwparams) < 0) { + term(); + return false; + } + + if(snd_pcm_hw_params_set_access(device.handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0 + || snd_pcm_hw_params_set_format(device.handle, hwparams, device.format) < 0 + || snd_pcm_hw_params_set_channels(device.handle, hwparams, device.channels) < 0 + || snd_pcm_hw_params_set_rate_near(device.handle, hwparams, &rate, 0) < 0 + || snd_pcm_hw_params_set_period_time_near(device.handle, hwparams, &period_time, 0) < 0 + || snd_pcm_hw_params_set_buffer_time_near(device.handle, hwparams, &buffer_time, 0) < 0 + ) { + term(); + return false; + } + + if(snd_pcm_hw_params(device.handle, hwparams) < 0) { + term(); + return false; + } + + if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) { + term(); + return false; + } + + snd_pcm_sw_params_alloca(&swparams); + if(snd_pcm_sw_params_current(device.handle, swparams) < 0) { + term(); + return false; + } + + if(snd_pcm_sw_params_set_start_threshold(device.handle, swparams, + (device.buffer_size / device.period_size) * device.period_size) < 0 + ) { + term(); + return false; + } + + if(snd_pcm_sw_params(device.handle, swparams) < 0) { + term(); + return false; + } + + buffer.data = new uint32_t[device.period_size]; + return true; + } + + void term() { + if(device.handle) { + snd_pcm_drain(device.handle); + snd_pcm_close(device.handle); + device.handle = 0; + } + + if(buffer.data) { + delete[] buffer.data; + buffer.data = 0; + } + } + + pAudioALSA() { + device.handle = 0; + device.format = SND_PCM_FORMAT_S16_LE; + device.channels = 2; + device.name = "default"; + + buffer.data = 0; + buffer.length = 0; + + settings.synchronize = false; + settings.frequency = 22050; + settings.latency = 60; + } + + ~pAudioALSA() { + term(); + } +}; + +DeclareAudio(ALSA) + +}; diff --git a/ruby/audio/ao.cpp b/ruby/audio/ao.cpp new file mode 100755 index 00000000..0cfe670d --- /dev/null +++ b/ruby/audio/ao.cpp @@ -0,0 +1,94 @@ +/* + audio.ao (2008-06-01) + authors: Nach, RedDwarf +*/ + +#include + +namespace ruby { + +class pAudioAO { +public: + int driver_id; + ao_sample_format driver_format; + ao_device *audio_device; + + struct { + unsigned frequency; + } settings; + + bool cap(const string& name) { + if(name == Audio::Frequency) return true; + return false; + } + + any get(const string& name) { + if(name == Audio::Frequency) return settings.frequency; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Audio::Frequency) { + settings.frequency = any_cast(value); + if(audio_device) init(); + return true; + } + + return false; + } + + void sample(uint16_t l_sample, uint16_t r_sample) { + uint32_t samp = (l_sample << 0) + (r_sample << 16); + ao_play(audio_device, (char*)&samp, 4); //This may need to be byte swapped for Big Endian + } + + void clear() { + } + + bool init() { + term(); + + driver_id = ao_default_driver_id(); //ao_driver_id((const char*)driver) + if(driver_id < 0) return false; + + driver_format.bits = 16; + driver_format.channels = 2; + driver_format.rate = settings.frequency; + driver_format.byte_format = AO_FMT_LITTLE; + + ao_option *options = 0; + ao_info *di = ao_driver_info(driver_id); + if(!di) return false; + if(!strcmp(di->short_name, "alsa")) { + ao_append_option(&options, "buffer_time", "100000"); //100ms latency (default was 500ms) + } + + audio_device = ao_open_live(driver_id, &driver_format, options); + if(!audio_device) return false; + + return true; + } + + void term() { + if(audio_device) { + ao_close(audio_device); + audio_device = 0; + } + } + + pAudioAO() { + audio_device = 0; + ao_initialize(); + + settings.frequency = 22050; + } + + ~pAudioAO() { + term(); + //ao_shutdown(); //FIXME: this is causing a segfault for some reason when called ... + } +}; + +DeclareAudio(AO) + +}; diff --git a/ruby/audio/directsound.cpp b/ruby/audio/directsound.cpp new file mode 100755 index 00000000..17d09e23 --- /dev/null +++ b/ruby/audio/directsound.cpp @@ -0,0 +1,212 @@ +/* + audio.directsound (2007-12-26) + author: byuu +*/ + +#include + +namespace ruby { + +class pAudioDS { +public: + LPDIRECTSOUND ds; + LPDIRECTSOUNDBUFFER dsb_p, dsb_b; + DSBUFFERDESC dsbd; + WAVEFORMATEX wfx; + + struct { + unsigned rings; + unsigned latency; + + uint32_t *buffer; + unsigned bufferoffset; + + unsigned readring; + unsigned writering; + int distance; + } device; + + struct { + HWND handle; + bool synchronize; + unsigned frequency; + unsigned latency; + } settings; + + bool cap(const string& name) { + if(name == Audio::Handle) return true; + if(name == Audio::Synchronize) return true; + if(name == Audio::Frequency) return true; + if(name == Audio::Latency) return true; + return false; + } + + any get(const string& name) { + if(name == Audio::Handle) return (uintptr_t)settings.handle; + if(name == Audio::Synchronize) return settings.synchronize; + if(name == Audio::Frequency) return settings.frequency; + if(name == Audio::Latency) return settings.latency; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Audio::Handle) { + settings.handle = (HWND)any_cast(value); + return true; + } + + if(name == Audio::Synchronize) { + settings.synchronize = any_cast(value); + if(ds) clear(); + return true; + } + + if(name == Audio::Frequency) { + settings.frequency = any_cast(value); + if(ds) init(); + return true; + } + + if(name == Audio::Latency) { + settings.latency = any_cast(value); + if(ds) init(); + return true; + } + + return false; + } + + void sample(uint16_t left, uint16_t right) { + device.buffer[device.bufferoffset++] = left + (right << 16); + if(device.bufferoffset < device.latency) return; + device.bufferoffset = 0; + + DWORD pos, size; + void *output; + + if(settings.synchronize == true) { + //wait until playback buffer has an empty ring to write new audio data to + while(device.distance >= device.rings - 1) { + dsb_b->GetCurrentPosition(&pos, 0); + unsigned activering = pos / (device.latency * 4); + if(activering == device.readring) { + if(settings.synchronize == false) Sleep(1); + continue; + } + + //subtract number of played rings from ring distance counter + device.distance -= (device.rings + activering - device.readring) % device.rings; + device.readring = activering; + + if(device.distance < 2) { + //buffer underflow; set max distance to recover quickly + device.distance = device.rings - 1; + device.writering = (device.rings + device.readring - 1) % device.rings; + break; + } + } + } + + device.writering = (device.writering + 1) % device.rings; + device.distance = (device.distance + 1) % device.rings; + + if(dsb_b->Lock(device.writering * device.latency * 4, device.latency * 4, &output, &size, 0, 0, 0) == DS_OK) { + memcpy(output, device.buffer, device.latency * 4); + dsb_b->Unlock(output, size, 0, 0); + } + } + + void clear() { + device.readring = 0; + device.writering = device.rings - 1; + device.distance = device.rings - 1; + + device.bufferoffset = 0; + if(device.buffer) memset(device.buffer, 0, device.latency * device.rings * 4); + + if(!dsb_b) return; + dsb_b->Stop(); + dsb_b->SetCurrentPosition(0); + + DWORD size; + void *output; + dsb_b->Lock(0, device.latency * device.rings * 4, &output, &size, 0, 0, 0); + memset(output, 0, size); + dsb_b->Unlock(output, size, 0, 0); + + dsb_b->Play(0, 0, DSBPLAY_LOOPING); + } + + bool init() { + term(); + + device.rings = 8; + device.latency = settings.frequency * settings.latency / device.rings / 1000.0 + 0.5; + device.buffer = new uint32_t[device.latency * device.rings]; + device.bufferoffset = 0; + + DirectSoundCreate(0, &ds, 0); + ds->SetCooperativeLevel((HWND)settings.handle, DSSCL_PRIORITY); + + memset(&dsbd, 0, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = 0; + ds->CreateSoundBuffer(&dsbd, &dsb_p, 0); + + memset(&wfx, 0, sizeof(wfx)); + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = 2; + wfx.nSamplesPerSec = settings.frequency; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + dsb_p->SetFormat(&wfx); + + memset(&dsbd, 0, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE; + dsbd.dwBufferBytes = device.latency * device.rings * sizeof(uint32_t); + dsbd.guid3DAlgorithm = GUID_NULL; + dsbd.lpwfxFormat = &wfx; + ds->CreateSoundBuffer(&dsbd, &dsb_b, 0); + dsb_b->SetFrequency(settings.frequency); + dsb_b->SetCurrentPosition(0); + + clear(); + return true; + } + + void term() { + if(device.buffer) { + delete[] device.buffer; + device.buffer = 0; + } + + if(dsb_b) { dsb_b->Stop(); dsb_b->Release(); dsb_b = 0; } + if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = 0; } + if(ds) { ds->Release(); ds = 0; } + } + + pAudioDS() { + ds = 0; + dsb_p = 0; + dsb_b = 0; + + device.buffer = 0; + device.bufferoffset = 0; + device.readring = 0; + device.writering = 0; + device.distance = 0; + + settings.handle = GetDesktopWindow(); + settings.synchronize = false; + settings.frequency = 22050; + settings.latency = 120; + } +}; + +DeclareAudio(DS) + +}; diff --git a/ruby/audio/openal.cpp b/ruby/audio/openal.cpp new file mode 100755 index 00000000..a5be2aac --- /dev/null +++ b/ruby/audio/openal.cpp @@ -0,0 +1,210 @@ +/* + audio.openal (2007-12-26) + author: Nach + contributors: byuu, wertigon, _willow_ +*/ + +#if defined(PLATFORM_OSX) + #include + #include +#else + #include + #include +#endif + +namespace ruby { + +class pAudioOpenAL { +public: + struct { + ALCdevice *handle; + ALCcontext *context; + ALuint source; + ALenum format; + unsigned latency; + unsigned queue_length; + } device; + + struct { + uint32_t *data; + unsigned length; + unsigned size; + } buffer; + + struct { + bool synchronize; + unsigned frequency; + unsigned latency; + } settings; + + bool cap(const string& name) { + if(name == Audio::Synchronize) return true; + if(name == Audio::Frequency) return true; + if(name == Audio::Latency) return true; + return false; + } + + any get(const string& name) { + if(name == Audio::Synchronize) return settings.synchronize; + if(name == Audio::Frequency) return settings.frequency; + if(name == Audio::Latency) return settings.latency; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Audio::Synchronize) { + settings.synchronize = any_cast(value); + return true; + } + + if(name == Audio::Frequency) { + settings.frequency = any_cast(value); + return true; + } + + if(name == Audio::Latency) { + if(settings.latency != any_cast(value)) { + settings.latency = any_cast(value); + update_latency(); + } + return true; + } + + return false; + } + + void sample(uint16_t sl, uint16_t sr) { + buffer.data[buffer.length++] = sl + (sr << 16); + if(buffer.length < buffer.size) return; + + ALuint albuffer = 0; + int processed = 0; + while(true) { + alGetSourcei(device.source, AL_BUFFERS_PROCESSED, &processed); + while(processed--) { + alSourceUnqueueBuffers(device.source, 1, &albuffer); + alDeleteBuffers(1, &albuffer); + device.queue_length--; + } + //wait for buffer playback to catch up to sample generation if not synchronizing + if(settings.synchronize == false || device.queue_length < 3) break; + } + + if(device.queue_length < 3) { + alGenBuffers(1, &albuffer); + alBufferData(albuffer, device.format, buffer.data, buffer.size * 4, settings.frequency); + alSourceQueueBuffers(device.source, 1, &albuffer); + device.queue_length++; + } + + ALint playing; + alGetSourcei(device.source, AL_SOURCE_STATE, &playing); + if(playing != AL_PLAYING) alSourcePlay(device.source); + buffer.length = 0; + } + + void clear() { + } + + void update_latency() { + if(buffer.data) delete[] buffer.data; + buffer.size = settings.frequency * settings.latency / 1000.0 + 0.5; + buffer.data = new uint32_t[buffer.size]; + } + + bool init() { + update_latency(); + device.queue_length = 0; + + bool success = false; + if(device.handle = alcOpenDevice(NULL)) { + if(device.context = alcCreateContext(device.handle, NULL)) { + alcMakeContextCurrent(device.context); + alGenSources(1, &device.source); + + //alSourcef (device.source, AL_PITCH, 1.0); + //alSourcef (device.source, AL_GAIN, 1.0); + //alSource3f(device.source, AL_POSITION, 0.0, 0.0, 0.0); + //alSource3f(device.source, AL_VELOCITY, 0.0, 0.0, 0.0); + //alSource3f(device.source, AL_DIRECTION, 0.0, 0.0, 0.0); + //alSourcef (device.source, AL_ROLLOFF_FACTOR, 0.0); + //alSourcei (device.source, AL_SOURCE_RELATIVE, AL_TRUE); + + alListener3f(AL_POSITION, 0.0, 0.0, 0.0); + alListener3f(AL_VELOCITY, 0.0, 0.0, 0.0); + ALfloat listener_orientation[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + alListenerfv(AL_ORIENTATION, listener_orientation); + + success = true; + } + } + + if(success == false) { + term(); + return false; + } + + return true; + } + + void term() { + if(alIsSource(device.source) == AL_TRUE) { + int playing = 0; + alGetSourcei(device.source, AL_SOURCE_STATE, &playing); + if(playing == AL_PLAYING) { + alSourceStop(device.source); + int queued = 0; + alGetSourcei(device.source, AL_BUFFERS_QUEUED, &queued); + while(queued--) { + ALuint albuffer = 0; + alSourceUnqueueBuffers(device.source, 1, &albuffer); + alDeleteBuffers(1, &albuffer); + device.queue_length--; + } + } + + alDeleteSources(1, &device.source); + device.source = 0; + } + + if(device.context) { + alcMakeContextCurrent(NULL); + alcDestroyContext(device.context); + device.context = 0; + } + + if(device.handle) { + alcCloseDevice(device.handle); + device.handle = 0; + } + + if(buffer.data) { + delete[] buffer.data; + buffer.data = 0; + } + } + + pAudioOpenAL() { + device.source = 0; + device.handle = 0; + device.context = 0; + device.format = AL_FORMAT_STEREO16; + device.queue_length = 0; + + buffer.data = 0; + buffer.length = 0; + buffer.size = 0; + + settings.synchronize = true; + settings.frequency = 22050; + settings.latency = 40; + } + + ~pAudioOpenAL() { + term(); + } +}; + +DeclareAudio(OpenAL) + +}; diff --git a/ruby/audio/oss.cpp b/ruby/audio/oss.cpp new file mode 100755 index 00000000..dcb8115c --- /dev/null +++ b/ruby/audio/oss.cpp @@ -0,0 +1,113 @@ +/* + audio.oss (2007-12-26) + author: Nach +*/ + +#include +#include +#include +#include + +//OSS4 soundcard.h includes below SNDCTL defines, but OSS3 does not +//However, OSS4 soundcard.h does not reside in +//Therefore, attempt to manually define SNDCTL values if using OSS3 header +//Note that if the defines below fail to work on any specific platform, one can point soundcard.h +//above to the correct location for OSS4 (usually /usr/lib/oss/include/sys/soundcard.h) +//Failing that, one can disable OSS4 ioctl calls inside init() and remove the below defines + +#ifndef SNDCTL_DSP_COOKEDMODE + #define SNDCTL_DSP_COOKEDMODE _IOW('P', 30, int) +#endif + +#ifndef SNDCTL_DSP_POLICY + #define SNDCTL_DSP_POLICY _IOW('P', 45, int) +#endif + +namespace ruby { + +class pAudioOSS { +public: + struct { + int fd; + int format; + int channels; + const char *name; + } device; + + struct { + unsigned frequency; + } settings; + + bool cap(const string& name) { + if(name == Audio::Frequency) return true; + return false; + } + + any get(const string& name) { + if(name == Audio::Frequency) return settings.frequency; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Audio::Frequency) { + settings.frequency = any_cast(value); + if(device.fd > 0) init(); + return true; + } + + return false; + } + + void sample(uint16_t sl, uint16_t sr) { + uint32_t sample = sl + (sr << 16); + unsigned unused = write(device.fd, &sample, 4); + } + + void clear() { + } + + bool init() { + term(); + + device.fd = open(device.name, O_WRONLY, O_NONBLOCK); + if(device.fd < 0) return false; + + #if 1 //SOUND_VERSION >= 0x040000 + //attempt to enable OSS4-specific features regardless of version + //OSS3 ioctl calls will silently fail, but sound will still work + int cooked = 1, policy = 4; //policy should be 0 - 10, lower = less latency, more CPU usage + ioctl(device.fd, SNDCTL_DSP_COOKEDMODE, &cooked); + ioctl(device.fd, SNDCTL_DSP_POLICY, &policy); + #endif + int freq = settings.frequency; + ioctl(device.fd, SNDCTL_DSP_CHANNELS, &device.channels); + ioctl(device.fd, SNDCTL_DSP_SETFMT, &device.format); + ioctl(device.fd, SNDCTL_DSP_SPEED, &freq); + + return true; + } + + void term() { + if(device.fd > 0) { + close(device.fd); + device.fd = -1; + } + } + + pAudioOSS() { + device.fd = -1; + device.format = AFMT_S16_LE; + device.channels = 2; + device.name = "/dev/dsp"; + + settings.frequency = 22050; + } + + ~pAudioOSS() { + term(); + } +}; + +DeclareAudio(OSS) + +}; diff --git a/ruby/audio/pulseaudio.cpp b/ruby/audio/pulseaudio.cpp new file mode 100755 index 00000000..bdd5f682 --- /dev/null +++ b/ruby/audio/pulseaudio.cpp @@ -0,0 +1,177 @@ +//audio.pulseaudio (2010-01-05) +//author: RedDwarf + +#include + +namespace ruby { + +class pAudioPulseAudio { +public: + struct { + pa_mainloop *mainloop; + pa_context *context; + pa_stream *stream; + pa_sample_spec spec; + pa_buffer_attr buffer_attr; + bool first; + } device; + + struct { + uint32_t *data; + size_t size; + unsigned offset; + } buffer; + + struct { + bool synchronize; + unsigned frequency; + unsigned latency; + } settings; + + bool cap(const string& name) { + if(name == Audio::Synchronize) return true; + if(name == Audio::Frequency) return true; + if(name == Audio::Latency) return true; + } + + any get(const string& name) { + if(name == Audio::Synchronize) return settings.synchronize; + if(name == Audio::Frequency) return settings.frequency; + if(name == Audio::Latency) return settings.latency; + } + + bool set(const string& name, const any& value) { + if(name == Audio::Synchronize) { + settings.synchronize = any_cast(value); + return true; + } + + if(name == Audio::Frequency) { + settings.frequency = any_cast(value); + if(device.stream) { + pa_operation_unref(pa_stream_update_sample_rate(device.stream, settings.frequency, NULL, NULL)); + } + return true; + } + + if(name == Audio::Latency) { + settings.latency = any_cast(value); + if(device.stream) { + device.buffer_attr.tlength = pa_usec_to_bytes(settings.latency * PA_USEC_PER_MSEC, &device.spec); + pa_stream_set_buffer_attr(device.stream, &device.buffer_attr, NULL, NULL); + } + return true; + } + } + + void sample(uint16_t left, uint16_t right) { + pa_stream_begin_write(device.stream, (void**)&buffer.data, &buffer.size); + buffer.data[buffer.offset++] = left + (right << 16); + if((buffer.offset + 1) * pa_frame_size(&device.spec) <= buffer.size) return; + + while(true) { + if(device.first) { + device.first = false; + pa_mainloop_iterate(device.mainloop, 0, NULL); + } else { + pa_mainloop_iterate(device.mainloop, 1, NULL); + } + unsigned length = pa_stream_writable_size(device.stream); + if(length >= buffer.offset * pa_frame_size(&device.spec)) break; + if(settings.synchronize == false) { + buffer.offset = 0; + return; + } + } + + pa_stream_write(device.stream, (const void*)buffer.data, buffer.offset * pa_frame_size(&device.spec), NULL, 0LL, PA_SEEK_RELATIVE); + buffer.data = 0; + buffer.offset = 0; + } + + void clear() { + } + + bool init() { + device.mainloop = pa_mainloop_new(); + + device.context = pa_context_new(pa_mainloop_get_api(device.mainloop), "ruby::pulseaudio"); + pa_context_connect(device.context, NULL, PA_CONTEXT_NOFLAGS, NULL); + + pa_context_state_t cstate; + do { + pa_mainloop_iterate(device.mainloop, 1, NULL); + cstate = pa_context_get_state(device.context); + if(!PA_CONTEXT_IS_GOOD(cstate)) return false; + } while(cstate != PA_CONTEXT_READY); + + device.spec.format = PA_SAMPLE_S16LE; + device.spec.channels = 2; + device.spec.rate = settings.frequency; + device.stream = pa_stream_new(device.context, "audio", &device.spec, NULL); + + device.buffer_attr.maxlength = -1; + device.buffer_attr.tlength = pa_usec_to_bytes(settings.latency * PA_USEC_PER_MSEC, &device.spec); + device.buffer_attr.prebuf = -1; + device.buffer_attr.minreq = -1; + device.buffer_attr.fragsize = -1; + + pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY | PA_STREAM_VARIABLE_RATE); + pa_stream_connect_playback(device.stream, NULL, &device.buffer_attr, flags, NULL, NULL); + + pa_stream_state_t sstate; + do { + pa_mainloop_iterate(device.mainloop, 1, NULL); + sstate = pa_stream_get_state(device.stream); + if(!PA_STREAM_IS_GOOD(sstate)) return false; + } while(sstate != PA_STREAM_READY); + + buffer.size = 960; + buffer.offset = 0; + device.first = true; + + return true; + } + + void term() { + if(buffer.data) { + pa_stream_cancel_write(device.stream); + buffer.data = 0; + } + + if(device.stream) { + pa_stream_disconnect(device.stream); + pa_stream_unref(device.stream); + device.stream = 0; + } + + if(device.context) { + pa_context_disconnect(device.context); + pa_context_unref(device.context); + device.context = 0; + } + + if(device.mainloop) { + pa_mainloop_free(device.mainloop); + device.mainloop = 0; + } + } + + pAudioPulseAudio() { + device.mainloop = 0; + device.context = 0; + device.stream = 0; + buffer.data = 0; + settings.synchronize = false; + settings.frequency = 22050; + settings.latency = 60; + } + + ~pAudioPulseAudio() { + term(); + } +}; + +DeclareAudio(PulseAudio) + +} diff --git a/ruby/audio/pulseaudiosimple.cpp b/ruby/audio/pulseaudiosimple.cpp new file mode 100755 index 00000000..cdd6e438 --- /dev/null +++ b/ruby/audio/pulseaudiosimple.cpp @@ -0,0 +1,115 @@ +//audio.pulseaudiosimple (2010-01-05) +//author: byuu + +#include +#include + +namespace ruby { + +class pAudioPulseAudioSimple { +public: + struct { + pa_simple *handle; + pa_sample_spec spec; + } device; + + struct { + uint32_t *data; + unsigned offset; + } buffer; + + struct { + unsigned frequency; + } settings; + + bool cap(const string& name) { + if(name == Audio::Frequency) return true; + return false; + } + + any get(const string& name) { + if(name == Audio::Frequency) return settings.frequency; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Audio::Frequency) { + settings.frequency = any_cast(value); + if(device.handle) init(); + return true; + } + + return false; + } + + void sample(uint16_t left, uint16_t right) { + if(!device.handle) return; + + buffer.data[buffer.offset++] = left + (right << 16); + if(buffer.offset >= 64) { + int error; + pa_simple_write(device.handle, (const void*)buffer.data, buffer.offset * sizeof(uint32_t), &error); + buffer.offset = 0; + } + } + + void clear() { + } + + bool init() { + term(); + + device.spec.format = PA_SAMPLE_S16LE; + device.spec.channels = 2; + device.spec.rate = settings.frequency; + + int error = 0; + device.handle = pa_simple_new( + 0, //default server + "ruby::pulseaudiosimple", //application name + PA_STREAM_PLAYBACK, //direction + 0, //default device + "audio", //stream description + &device.spec, //sample format + 0, //default channel map + 0, //default buffering attributes + &error //error code + ); + if(!device.handle) { + fprintf(stderr, "ruby::pulseaudiosimple failed to initialize - %s\n", pa_strerror(error)); + return false; + } + + buffer.data = new uint32_t[64]; + buffer.offset = 0; + return true; + } + + void term() { + if(device.handle) { + int error; + pa_simple_flush(device.handle, &error); + pa_simple_free(device.handle); + device.handle = 0; + } + + if(buffer.data) { + delete[] buffer.data; + buffer.data = 0; + } + } + + pAudioPulseAudioSimple() { + device.handle = 0; + buffer.data = 0; + settings.frequency = 22050; + } + + ~pAudioPulseAudioSimple() { + term(); + } +}; + +DeclareAudio(PulseAudioSimple) + +}; diff --git a/ruby/audio/xaudio2.cpp b/ruby/audio/xaudio2.cpp new file mode 100755 index 00000000..d6298593 --- /dev/null +++ b/ruby/audio/xaudio2.cpp @@ -0,0 +1,200 @@ +/* + audio.xaudio2 (2010-08-14) + author: OV2 +*/ + +#include "xaudio2.hpp" +#include + +namespace ruby { + +class pAudioXAudio2: public IXAudio2VoiceCallback { +public: + IXAudio2 *pXAudio2; + IXAudio2MasteringVoice* pMasterVoice; + IXAudio2SourceVoice *pSourceVoice; + + // inherited from IXAudio2VoiceCallback + STDMETHODIMP_(void) OnBufferStart(void *pBufferContext){} + STDMETHODIMP_(void) OnLoopEnd(void *pBufferContext){} + STDMETHODIMP_(void) OnStreamEnd() {} + STDMETHODIMP_(void) OnVoiceError(void *pBufferContext, HRESULT Error) {} + STDMETHODIMP_(void) OnVoiceProcessingPassEnd() {} + STDMETHODIMP_(void) OnVoiceProcessingPassStart(UINT32 BytesRequired) {} + + struct { + unsigned buffers; + unsigned latency; + + uint32_t *buffer; + unsigned bufferoffset; + + volatile long submitbuffers; + unsigned writebuffer; + } device; + + struct { + bool synchronize; + unsigned frequency; + unsigned latency; + } settings; + + bool cap(const string& name) { + if(name == Audio::Synchronize) return true; + if(name == Audio::Frequency) return true; + if(name == Audio::Latency) return true; + return false; + } + + any get(const string& name) { + if(name == Audio::Synchronize) return settings.synchronize; + if(name == Audio::Frequency) return settings.frequency; + if(name == Audio::Latency) return settings.latency; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Audio::Synchronize) { + settings.synchronize = any_cast(value); + if(pXAudio2) clear(); + return true; + } + + if(name == Audio::Frequency) { + settings.frequency = any_cast(value); + if(pXAudio2) init(); + return true; + } + + if(name == Audio::Latency) { + settings.latency = any_cast(value); + if(pXAudio2) init(); + return true; + } + + return false; + } + + void pushbuffer(unsigned bytes,uint32_t *pAudioData) { + XAUDIO2_BUFFER xa2buffer={0}; + xa2buffer.AudioBytes=bytes; + xa2buffer.pAudioData=reinterpret_cast(pAudioData); + xa2buffer.pContext=0; + InterlockedIncrement(&device.submitbuffers); + pSourceVoice->SubmitSourceBuffer(&xa2buffer); + } + + void sample(uint16_t left, uint16_t right) { + device.buffer[device.writebuffer * device.latency + device.bufferoffset++] = left + (right << 16); + if(device.bufferoffset < device.latency) return; + device.bufferoffset = 0; + + if(device.submitbuffers == device.buffers - 1) { + if(settings.synchronize == true) { + //wait until there is at least one other free buffer for the next sample + while(device.submitbuffers == device.buffers - 1) { + //Sleep(0); + } + } else { //we need one free buffer for the next sample, so ignore the current contents + return; + } + } + + pushbuffer(device.latency * 4,device.buffer + device.writebuffer * device.latency); + + device.writebuffer = (device.writebuffer + 1) % device.buffers; + } + + void clear() { + if(!pSourceVoice) return; + pSourceVoice->Stop(0); + pSourceVoice->FlushSourceBuffers(); //calls OnBufferEnd for all currently submitted buffers + + device.writebuffer = 0; + + device.bufferoffset = 0; + if(device.buffer) memset(device.buffer, 0, device.latency * device.buffers * 4); + + pSourceVoice->Start(0); + } + + bool init() { + term(); + + device.buffers = 8; + device.latency = settings.frequency * settings.latency / device.buffers / 1000.0 + 0.5; + device.buffer = new uint32_t[device.latency * device.buffers]; + device.bufferoffset = 0; + device.submitbuffers = 0; + + HRESULT hr; + if(FAILED(hr = XAudio2Create(&pXAudio2, 0 , XAUDIO2_DEFAULT_PROCESSOR))) { + return false; + } + + if(FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, 2, + settings.frequency, 0, 0 , NULL))) { + return false; + } + + WAVEFORMATEX wfx; + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = 2; + wfx.nSamplesPerSec = settings.frequency; + wfx.nBlockAlign = 4; + wfx.wBitsPerSample = 16; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + wfx.cbSize = 0; + + if(FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx, + XAUDIO2_VOICE_NOSRC , XAUDIO2_DEFAULT_FREQ_RATIO, this, NULL, NULL))) { + return false; + } + + clear(); + return true; + } + + void term() { + if(pSourceVoice) { + pSourceVoice->Stop(0); + pSourceVoice->DestroyVoice(); + pSourceVoice = 0; + } + if(pMasterVoice) { + pMasterVoice->DestroyVoice(); + pMasterVoice = 0; + } + if(pXAudio2) { + pXAudio2->Release(); + pXAudio2 = NULL; + } + if(device.buffer) { + delete[] device.buffer; + device.buffer = 0; + } + } + + STDMETHODIMP_(void) OnBufferEnd(void *pBufferContext) { + InterlockedDecrement(&device.submitbuffers); + } + + pAudioXAudio2() { + pXAudio2 = 0; + pMasterVoice = 0; + pSourceVoice = 0; + + device.buffer = 0; + device.bufferoffset = 0; + device.submitbuffers = 0; + device.writebuffer = 0; + + settings.synchronize = false; + settings.frequency = 22050; + settings.latency = 120; + } +}; + +DeclareAudio(XAudio2) + +}; diff --git a/ruby/audio/xaudio2.hpp b/ruby/audio/xaudio2.hpp new file mode 100755 index 00000000..e283f503 --- /dev/null +++ b/ruby/audio/xaudio2.hpp @@ -0,0 +1,340 @@ +/* + xaudio2.hpp (2010-08-14) + author: OV2 + + ruby-specific header to provide mingw-friendly xaudio2 interfaces +*/ + +#ifndef XAUDIO2_RUBY_H +#define XAUDIO2_RUBY_H + +//64-bit GCC fix +#define GUID_EXT EXTERN_C +#define GUID_SECT + +#include + +#define DEFINE_GUID_X(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) GUID_EXT const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} +#define DEFINE_CLSID_X(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + DEFINE_GUID_X(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) +#define DEFINE_IID_X(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + DEFINE_GUID_X(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) +#define X2DEFAULT(x) =x + +DEFINE_CLSID_X(XAudio2, e21a7345, eb21, 468e, be, 50, 80, 4d, b9, 7c, f7, 08); +DEFINE_CLSID_X(XAudio2_Debug, f7a76c21, 53d4, 46bb, ac, 53, 8b, 45, 9c, ae, 46, bd); +DEFINE_IID_X(IXAudio2, 8bcf1f58, 9fe7, 4583, 8a, c6, e2, ad, c4, 65, c8, bb); + +DECLARE_INTERFACE(IXAudio2Voice); + +#define XAUDIO2_COMMIT_NOW 0 +#define XAUDIO2_DEFAULT_CHANNELS 0 +#define XAUDIO2_DEFAULT_SAMPLERATE 0 +#define XAUDIO2_DEFAULT_FREQ_RATIO 4.0f +#define XAUDIO2_DEBUG_ENGINE 0x0001 +#define XAUDIO2_VOICE_NOSRC 0x0004 + +typedef struct +{ + WAVEFORMATEX Format; + union + { + WORD wValidBitsPerSample; + WORD wSamplesPerBlock; + WORD wReserved; + } Samples; + DWORD dwChannelMask; + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPPWAVEFORMATEXTENSIBLE; +typedef const WAVEFORMATEXTENSIBLE* LPCWAVEFORMATEXTENSIBLE; + +typedef enum XAUDIO2_DEVICE_ROLE +{ + NotDefaultDevice = 0x0, + DefaultConsoleDevice = 0x1, + DefaultMultimediaDevice = 0x2, + DefaultCommunicationsDevice = 0x4, + DefaultGameDevice = 0x8, + GlobalDefaultDevice = 0xf, + InvalidDeviceRole = ~GlobalDefaultDevice +} XAUDIO2_DEVICE_ROLE; + +typedef struct XAUDIO2_DEVICE_DETAILS +{ + WCHAR DeviceID[256]; + WCHAR DisplayName[256]; + XAUDIO2_DEVICE_ROLE Role; + WAVEFORMATEXTENSIBLE OutputFormat; +} XAUDIO2_DEVICE_DETAILS; + +typedef struct XAUDIO2_VOICE_DETAILS +{ + UINT32 CreationFlags; + UINT32 InputChannels; + UINT32 InputSampleRate; +} XAUDIO2_VOICE_DETAILS; + +typedef enum XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER +{ + Processor1 = 0x00000001, + Processor2 = 0x00000002, + Processor3 = 0x00000004, + Processor4 = 0x00000008, + Processor5 = 0x00000010, + Processor6 = 0x00000020, + Processor7 = 0x00000040, + Processor8 = 0x00000080, + Processor9 = 0x00000100, + Processor10 = 0x00000200, + Processor11 = 0x00000400, + Processor12 = 0x00000800, + Processor13 = 0x00001000, + Processor14 = 0x00002000, + Processor15 = 0x00004000, + Processor16 = 0x00008000, + Processor17 = 0x00010000, + Processor18 = 0x00020000, + Processor19 = 0x00040000, + Processor20 = 0x00080000, + Processor21 = 0x00100000, + Processor22 = 0x00200000, + Processor23 = 0x00400000, + Processor24 = 0x00800000, + Processor25 = 0x01000000, + Processor26 = 0x02000000, + Processor27 = 0x04000000, + Processor28 = 0x08000000, + Processor29 = 0x10000000, + Processor30 = 0x20000000, + Processor31 = 0x40000000, + Processor32 = 0x80000000, + XAUDIO2_ANY_PROCESSOR = 0xffffffff, + XAUDIO2_DEFAULT_PROCESSOR = XAUDIO2_ANY_PROCESSOR +} XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER, XAUDIO2_PROCESSOR; + +typedef struct XAUDIO2_VOICE_SENDS +{ + UINT32 OutputCount; + IXAudio2Voice** pOutputVoices; +} XAUDIO2_VOICE_SENDS; + +typedef struct XAUDIO2_EFFECT_DESCRIPTOR +{ + IUnknown* pEffect; + BOOL InitialState; + UINT32 OutputChannels; +} XAUDIO2_EFFECT_DESCRIPTOR; + +typedef struct XAUDIO2_EFFECT_CHAIN +{ + UINT32 EffectCount; + const XAUDIO2_EFFECT_DESCRIPTOR* pEffectDescriptors; +} XAUDIO2_EFFECT_CHAIN; + +typedef enum XAUDIO2_FILTER_TYPE +{ + LowPassFilter, + BandPassFilter, + HighPassFilter +} XAUDIO2_FILTER_TYPE; + +typedef struct XAUDIO2_FILTER_PARAMETERS +{ + XAUDIO2_FILTER_TYPE Type; + float Frequency; + float OneOverQ; + +} XAUDIO2_FILTER_PARAMETERS; + +typedef struct XAUDIO2_BUFFER +{ + UINT32 Flags; + UINT32 AudioBytes; + const BYTE* pAudioData; + UINT32 PlayBegin; + UINT32 PlayLength; + UINT32 LoopBegin; + UINT32 LoopLength; + UINT32 LoopCount; + void* pContext; +} XAUDIO2_BUFFER; + +typedef struct XAUDIO2_BUFFER_WMA +{ + const UINT32* pDecodedPacketCumulativeBytes; + UINT32 PacketCount; +} XAUDIO2_BUFFER_WMA; + +typedef struct XAUDIO2_VOICE_STATE +{ + void* pCurrentBufferContext; + UINT32 BuffersQueued; + UINT64 SamplesPlayed; +} XAUDIO2_VOICE_STATE; + +typedef struct XAUDIO2_PERFORMANCE_DATA +{ + UINT64 AudioCyclesSinceLastQuery; + UINT64 TotalCyclesSinceLastQuery; + UINT32 MinimumCyclesPerQuantum; + UINT32 MaximumCyclesPerQuantum; + UINT32 MemoryUsageInBytes; + UINT32 CurrentLatencyInSamples; + UINT32 GlitchesSinceEngineStarted; + UINT32 ActiveSourceVoiceCount; + UINT32 TotalSourceVoiceCount; + UINT32 ActiveSubmixVoiceCount; + UINT32 TotalSubmixVoiceCount; + UINT32 ActiveXmaSourceVoices; + UINT32 ActiveXmaStreams; +} XAUDIO2_PERFORMANCE_DATA; + +typedef struct XAUDIO2_DEBUG_CONFIGURATION +{ + UINT32 TraceMask; + UINT32 BreakMask; + BOOL LogThreadID; + BOOL LogFileline; + BOOL LogFunctionName; + BOOL LogTiming; +} XAUDIO2_DEBUG_CONFIGURATION; + +DECLARE_INTERFACE(IXAudio2EngineCallback) +{ + STDMETHOD_(void, OnProcessingPassStart) (THIS) PURE; + STDMETHOD_(void, OnProcessingPassEnd) (THIS) PURE; + STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT Error) PURE; +}; + +DECLARE_INTERFACE(IXAudio2VoiceCallback) +{ + STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 BytesRequired) PURE; + STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS) PURE; + STDMETHOD_(void, OnStreamEnd) (THIS) PURE; + STDMETHOD_(void, OnBufferStart) (THIS_ void* pBufferContext) PURE; + STDMETHOD_(void, OnBufferEnd) (THIS_ void* pBufferContext) PURE; + STDMETHOD_(void, OnLoopEnd) (THIS_ void* pBufferContext) PURE; + STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) PURE; +}; + +DECLARE_INTERFACE(IXAudio2Voice) +{ + #define Declare_IXAudio2Voice_Methods() \ + STDMETHOD_(void, GetVoiceDetails) (THIS_ XAUDIO2_VOICE_DETAILS* pVoiceDetails) PURE; \ + STDMETHOD(SetOutputVoices) (THIS_ const XAUDIO2_VOICE_SENDS* pSendList) PURE; \ + STDMETHOD(SetEffectChain) (THIS_ const XAUDIO2_EFFECT_CHAIN* pEffectChain) PURE; \ + STDMETHOD(EnableEffect) (THIS_ UINT32 EffectIndex, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + STDMETHOD(DisableEffect) (THIS_ UINT32 EffectIndex, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + STDMETHOD_(void, GetEffectState) (THIS_ UINT32 EffectIndex, BOOL* pEnabled) PURE; \ + STDMETHOD(SetEffectParameters) (THIS_ UINT32 EffectIndex, \ + const void* pParameters, \ + UINT32 ParametersByteSize, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + STDMETHOD(GetEffectParameters) (THIS_ UINT32 EffectIndex, void* pParameters, \ + UINT32 ParametersByteSize) PURE; \ + STDMETHOD(SetFilterParameters) (THIS_ const XAUDIO2_FILTER_PARAMETERS* pParameters, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + STDMETHOD_(void, GetFilterParameters) (THIS_ XAUDIO2_FILTER_PARAMETERS* pParameters) PURE; \ + STDMETHOD(SetVolume) (THIS_ float Volume, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + STDMETHOD_(void, GetVolume) (THIS_ float* pVolume) PURE; \ + STDMETHOD(SetChannelVolumes) (THIS_ UINT32 Channels, const float* pVolumes, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + STDMETHOD_(void, GetChannelVolumes) (THIS_ UINT32 Channels, float* pVolumes) PURE; \ + STDMETHOD(SetOutputMatrix) (THIS_ IXAudio2Voice* pDestinationVoice, \ + UINT32 SourceChannels, UINT32 DestinationChannels, \ + const float* pLevelMatrix, \ + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \ + STDMETHOD_(void, GetOutputMatrix) (THIS_ IXAudio2Voice* pDestinationVoice, \ + UINT32 SourceChannels, UINT32 DestinationChannels, \ + float* pLevelMatrix) PURE; \ + STDMETHOD_(void, DestroyVoice) (THIS) PURE + + Declare_IXAudio2Voice_Methods(); +}; + + +DECLARE_INTERFACE_(IXAudio2MasteringVoice, IXAudio2Voice) +{ + Declare_IXAudio2Voice_Methods(); +}; + +DECLARE_INTERFACE_(IXAudio2SubmixVoice, IXAudio2Voice) +{ + Declare_IXAudio2Voice_Methods(); +}; + +DECLARE_INTERFACE_(IXAudio2SourceVoice, IXAudio2Voice) +{ + Declare_IXAudio2Voice_Methods(); + STDMETHOD(Start) (THIS_ UINT32 Flags, UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; + STDMETHOD(Stop) (THIS_ UINT32 Flags, UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; + STDMETHOD(SubmitSourceBuffer) (THIS_ const XAUDIO2_BUFFER* pBuffer, const XAUDIO2_BUFFER_WMA* pBufferWMA X2DEFAULT(NULL)) PURE; + STDMETHOD(FlushSourceBuffers) (THIS) PURE; + STDMETHOD(Discontinuity) (THIS) PURE; + STDMETHOD(ExitLoop) (THIS_ UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; + STDMETHOD_(void, GetState) (THIS_ XAUDIO2_VOICE_STATE* pVoiceState) PURE; + STDMETHOD(SetFrequencyRatio) (THIS_ float Ratio, + UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; + STDMETHOD_(void, GetFrequencyRatio) (THIS_ float* pRatio) PURE; +}; + +DECLARE_INTERFACE_(IXAudio2, IUnknown) +{ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, void** ppvInterface) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + STDMETHOD(GetDeviceCount) (THIS_ UINT32* pCount) PURE; + STDMETHOD(GetDeviceDetails) (THIS_ UINT32 Index, XAUDIO2_DEVICE_DETAILS* pDeviceDetails) PURE; + STDMETHOD(Initialize) (THIS_ UINT32 Flags X2DEFAULT(0), + XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR)) PURE; + STDMETHOD(RegisterForCallbacks) (IXAudio2EngineCallback* pCallback) PURE; + STDMETHOD_(void, UnregisterForCallbacks) (IXAudio2EngineCallback* pCallback) PURE; + STDMETHOD(CreateSourceVoice) (THIS_ IXAudio2SourceVoice** ppSourceVoice, + const WAVEFORMATEX* pSourceFormat, + UINT32 Flags X2DEFAULT(0), + float MaxFrequencyRatio X2DEFAULT(XAUDIO2_DEFAULT_FREQ_RATIO), + IXAudio2VoiceCallback* pCallback X2DEFAULT(NULL), + const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL), + const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE; + STDMETHOD(CreateSubmixVoice) (THIS_ IXAudio2SubmixVoice** ppSubmixVoice, + UINT32 InputChannels, UINT32 InputSampleRate, + UINT32 Flags X2DEFAULT(0), UINT32 ProcessingStage X2DEFAULT(0), + const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL), + const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE; + STDMETHOD(CreateMasteringVoice) (THIS_ IXAudio2MasteringVoice** ppMasteringVoice, + UINT32 InputChannels X2DEFAULT(XAUDIO2_DEFAULT_CHANNELS), + UINT32 InputSampleRate X2DEFAULT(XAUDIO2_DEFAULT_SAMPLERATE), + UINT32 Flags X2DEFAULT(0), UINT32 DeviceIndex X2DEFAULT(0), + const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE; + STDMETHOD(StartEngine) (THIS) PURE; + STDMETHOD_(void, StopEngine) (THIS) PURE; + STDMETHOD(CommitChanges) (THIS_ UINT32 OperationSet) PURE; + STDMETHOD_(void, GetPerformanceData) (THIS_ XAUDIO2_PERFORMANCE_DATA* pPerfData) PURE; + STDMETHOD_(void, SetDebugConfiguration) (THIS_ const XAUDIO2_DEBUG_CONFIGURATION* pDebugConfiguration, + void* pReserved X2DEFAULT(NULL)) PURE; +}; + +__inline HRESULT XAudio2Create(IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0), + XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR)) +{ + IXAudio2* pXAudio2; + HRESULT hr = CoCreateInstance((Flags & XAUDIO2_DEBUG_ENGINE) ? CLSID_XAudio2_Debug : CLSID_XAudio2, + NULL, CLSCTX_INPROC_SERVER, IID_IXAudio2, (void**)&pXAudio2); + if (SUCCEEDED(hr)) + { + hr = pXAudio2->Initialize(Flags, XAudio2Processor); + if (SUCCEEDED(hr)) + { + *ppXAudio2 = pXAudio2; + } + else + { + pXAudio2->Release(); + } + } + return hr; +} +#endif diff --git a/ruby/input.hpp b/ruby/input.hpp new file mode 100755 index 00000000..5334c4da --- /dev/null +++ b/ruby/input.hpp @@ -0,0 +1,22 @@ +class Input { +public: + static const char *Handle; + static const char *KeyboardSupport; + static const char *MouseSupport; + static const char *JoypadSupport; + + virtual bool cap(const nall::string& name) { return false; } + virtual nall::any get(const nall::string& name) { return false; } + virtual bool set(const nall::string& name, const nall::any& value) { return false; } + + virtual bool acquire() { return false; } + virtual bool unacquire() { return false; } + virtual bool acquired() { return false; } + + virtual bool poll(int16_t *table) { return false; } + virtual bool init() { return true; } + virtual void term() {} + + Input() {} + virtual ~Input() {} +}; diff --git a/ruby/input/carbon.cpp b/ruby/input/carbon.cpp new file mode 100755 index 00000000..c5191f4b --- /dev/null +++ b/ruby/input/carbon.cpp @@ -0,0 +1,157 @@ +namespace ruby { + +class pInputCarbon { +public: + bool cap(const string& name) { + return false; + } + + any get(const string& name) { + return false; + } + + bool set(const string& name, const any& value) { + return false; + } + + bool acquire() { return false; } + bool unacquire() { return false; } + bool acquired() { return false; } + + bool poll(int16_t *table) { + memset(table, 0, Scancode::Limit * sizeof(int16_t)); + + KeyMap keys; + GetKeys(keys); + uint8_t *keymap = (uint8_t*)keys; + + #define map(id, name) table[keyboard(0)[name]] = (bool)(keymap[id >> 3] & (1 << (id & 7))) + map(0x35, Keyboard::Escape); + + map(0x7a, Keyboard::F1); + map(0x78, Keyboard::F2); + map(0x63, Keyboard::F3); + map(0x76, Keyboard::F4); + map(0x60, Keyboard::F5); + map(0x61, Keyboard::F6); + map(0x62, Keyboard::F7); + map(0x64, Keyboard::F8); + map(0x65, Keyboard::F9); + map(0x6d, Keyboard::F10); + map(0x67, Keyboard::F11); + //map(0x??, Keyboard::F12); + + map(0x69, Keyboard::PrintScreen); + //map(0x??, Keyboard::ScrollLock); + map(0x71, Keyboard::Pause); + + map(0x32, Keyboard::Tilde); + map(0x12, Keyboard::Num1); + map(0x13, Keyboard::Num2); + map(0x14, Keyboard::Num3); + map(0x15, Keyboard::Num4); + map(0x17, Keyboard::Num5); + map(0x16, Keyboard::Num6); + map(0x1a, Keyboard::Num7); + map(0x1c, Keyboard::Num8); + map(0x19, Keyboard::Num9); + map(0x1d, Keyboard::Num0); + + map(0x1b, Keyboard::Dash); + map(0x18, Keyboard::Equal); + map(0x33, Keyboard::Backspace); + + map(0x72, Keyboard::Insert); + map(0x75, Keyboard::Delete); + map(0x73, Keyboard::Home); + map(0x77, Keyboard::End); + map(0x74, Keyboard::PageUp); + map(0x79, Keyboard::PageDown); + + map(0x00, Keyboard::A); + map(0x0b, Keyboard::B); + map(0x08, Keyboard::C); + map(0x02, Keyboard::D); + map(0x0e, Keyboard::E); + map(0x03, Keyboard::F); + map(0x05, Keyboard::G); + map(0x04, Keyboard::H); + map(0x22, Keyboard::I); + map(0x26, Keyboard::J); + map(0x28, Keyboard::K); + map(0x25, Keyboard::L); + map(0x2e, Keyboard::M); + map(0x2d, Keyboard::N); + map(0x1f, Keyboard::O); + map(0x23, Keyboard::P); + map(0x0c, Keyboard::Q); + map(0x0f, Keyboard::R); + map(0x01, Keyboard::S); + map(0x11, Keyboard::T); + map(0x20, Keyboard::U); + map(0x09, Keyboard::V); + map(0x0d, Keyboard::W); + map(0x07, Keyboard::X); + map(0x10, Keyboard::Y); + map(0x06, Keyboard::Z); + + map(0x21, Keyboard::LeftBracket); + map(0x1e, Keyboard::RightBracket); + map(0x2a, Keyboard::Backslash); + map(0x29, Keyboard::Semicolon); + map(0x27, Keyboard::Apostrophe); + map(0x2b, Keyboard::Comma); + map(0x2f, Keyboard::Period); + map(0x2c, Keyboard::Slash); + + map(0x53, Keyboard::Keypad1); + map(0x54, Keyboard::Keypad2); + map(0x55, Keyboard::Keypad3); + map(0x56, Keyboard::Keypad4); + map(0x57, Keyboard::Keypad5); + map(0x58, Keyboard::Keypad6); + map(0x59, Keyboard::Keypad7); + map(0x5b, Keyboard::Keypad8); + map(0x5c, Keyboard::Keypad9); + map(0x52, Keyboard::Keypad0); + + //map(0x??, Keyboard::Point); + map(0x4c, Keyboard::Enter); + map(0x45, Keyboard::Add); + map(0x4e, Keyboard::Subtract); + map(0x43, Keyboard::Multiply); + map(0x4b, Keyboard::Divide); + + map(0x47, Keyboard::NumLock); + //map(0x39, Keyboard::CapsLock); + + map(0x7e, Keyboard::Up); + map(0x7d, Keyboard::Down); + map(0x7b, Keyboard::Left); + map(0x7c, Keyboard::Right); + + map(0x30, Keyboard::Tab); + map(0x24, Keyboard::Return); + map(0x31, Keyboard::Spacebar); + //map(0x??, Keyboard::Menu); + + map(0x38, Keyboard::Shift); + map(0x3b, Keyboard::Control); + map(0x3a, Keyboard::Alt); + map(0x37, Keyboard::Super); + #undef map + + return true; + } + + bool init() { + return true; + } + + void term() { + } +}; + +DeclareInput(Carbon) + +}; diff --git a/ruby/input/directinput.cpp b/ruby/input/directinput.cpp new file mode 100755 index 00000000..6db107b2 --- /dev/null +++ b/ruby/input/directinput.cpp @@ -0,0 +1,387 @@ +#define DIRECTINPUT_VERSION 0x0800 +#include + +namespace ruby { + +static BOOL CALLBACK DI_EnumJoypadsCallback(const DIDEVICEINSTANCE*, void*); +static BOOL CALLBACK DI_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE*, void*); + +using namespace nall; + +class pInputDI { +public: + struct { + LPDIRECTINPUT8 context; + LPDIRECTINPUTDEVICE8 keyboard; + LPDIRECTINPUTDEVICE8 mouse; + LPDIRECTINPUTDEVICE8 gamepad[Joypad::Count]; + bool mouseacquired; + } device; + + struct { + HWND handle; + } settings; + + bool cap(const string& name) { + if(name == Input::Handle) return true; + if(name == Input::KeyboardSupport) return true; + if(name == Input::MouseSupport) return true; + if(name == Input::JoypadSupport) return true; + return false; + } + + any get(const string& name) { + if(name == Input::Handle) return (uintptr_t)settings.handle; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Input::Handle) { + settings.handle = (HWND)any_cast(value); + return true; + } + + return false; + } + + bool poll(int16_t *table) { + memset(table, 0, Scancode::Limit * sizeof(int16_t)); + + //======== + //Keyboard + //======== + + if(device.keyboard) { + uint8_t state[256]; + if(FAILED(device.keyboard->GetDeviceState(sizeof state, state))) { + device.keyboard->Acquire(); + if(FAILED(device.keyboard->GetDeviceState(sizeof state, state))) { + memset(state, 0, sizeof state); + } + } + + #define key(id) table[keyboard(0)[id]] + + key(Keyboard::Escape) = (bool)(state[0x01] & 0x80); + key(Keyboard::F1 ) = (bool)(state[0x3b] & 0x80); + key(Keyboard::F2 ) = (bool)(state[0x3c] & 0x80); + key(Keyboard::F3 ) = (bool)(state[0x3d] & 0x80); + key(Keyboard::F4 ) = (bool)(state[0x3e] & 0x80); + key(Keyboard::F5 ) = (bool)(state[0x3f] & 0x80); + key(Keyboard::F6 ) = (bool)(state[0x40] & 0x80); + key(Keyboard::F7 ) = (bool)(state[0x41] & 0x80); + key(Keyboard::F8 ) = (bool)(state[0x42] & 0x80); + key(Keyboard::F9 ) = (bool)(state[0x43] & 0x80); + key(Keyboard::F10 ) = (bool)(state[0x44] & 0x80); + key(Keyboard::F11 ) = (bool)(state[0x57] & 0x80); + key(Keyboard::F12 ) = (bool)(state[0x58] & 0x80); + + key(Keyboard::PrintScreen) = (bool)(state[0xb7] & 0x80); + key(Keyboard::ScrollLock ) = (bool)(state[0x46] & 0x80); + key(Keyboard::Pause ) = (bool)(state[0xc5] & 0x80); + key(Keyboard::Tilde ) = (bool)(state[0x29] & 0x80); + + key(Keyboard::Num1) = (bool)(state[0x02] & 0x80); + key(Keyboard::Num2) = (bool)(state[0x03] & 0x80); + key(Keyboard::Num3) = (bool)(state[0x04] & 0x80); + key(Keyboard::Num4) = (bool)(state[0x05] & 0x80); + key(Keyboard::Num5) = (bool)(state[0x06] & 0x80); + key(Keyboard::Num6) = (bool)(state[0x07] & 0x80); + key(Keyboard::Num7) = (bool)(state[0x08] & 0x80); + key(Keyboard::Num8) = (bool)(state[0x09] & 0x80); + key(Keyboard::Num9) = (bool)(state[0x0a] & 0x80); + key(Keyboard::Num0) = (bool)(state[0x0b] & 0x80); + + key(Keyboard::Dash ) = (bool)(state[0x0c] & 0x80); + key(Keyboard::Equal ) = (bool)(state[0x0d] & 0x80); + key(Keyboard::Backspace) = (bool)(state[0x0e] & 0x80); + + key(Keyboard::Insert ) = (bool)(state[0xd2] & 0x80); + key(Keyboard::Delete ) = (bool)(state[0xd3] & 0x80); + key(Keyboard::Home ) = (bool)(state[0xc7] & 0x80); + key(Keyboard::End ) = (bool)(state[0xcf] & 0x80); + key(Keyboard::PageUp ) = (bool)(state[0xc9] & 0x80); + key(Keyboard::PageDown) = (bool)(state[0xd1] & 0x80); + + key(Keyboard::A) = (bool)(state[0x1e] & 0x80); + key(Keyboard::B) = (bool)(state[0x30] & 0x80); + key(Keyboard::C) = (bool)(state[0x2e] & 0x80); + key(Keyboard::D) = (bool)(state[0x20] & 0x80); + key(Keyboard::E) = (bool)(state[0x12] & 0x80); + key(Keyboard::F) = (bool)(state[0x21] & 0x80); + key(Keyboard::G) = (bool)(state[0x22] & 0x80); + key(Keyboard::H) = (bool)(state[0x23] & 0x80); + key(Keyboard::I) = (bool)(state[0x17] & 0x80); + key(Keyboard::J) = (bool)(state[0x24] & 0x80); + key(Keyboard::K) = (bool)(state[0x25] & 0x80); + key(Keyboard::L) = (bool)(state[0x26] & 0x80); + key(Keyboard::M) = (bool)(state[0x32] & 0x80); + key(Keyboard::N) = (bool)(state[0x31] & 0x80); + key(Keyboard::O) = (bool)(state[0x18] & 0x80); + key(Keyboard::P) = (bool)(state[0x19] & 0x80); + key(Keyboard::Q) = (bool)(state[0x10] & 0x80); + key(Keyboard::R) = (bool)(state[0x13] & 0x80); + key(Keyboard::S) = (bool)(state[0x1f] & 0x80); + key(Keyboard::T) = (bool)(state[0x14] & 0x80); + key(Keyboard::U) = (bool)(state[0x16] & 0x80); + key(Keyboard::V) = (bool)(state[0x2f] & 0x80); + key(Keyboard::W) = (bool)(state[0x11] & 0x80); + key(Keyboard::X) = (bool)(state[0x2d] & 0x80); + key(Keyboard::Y) = (bool)(state[0x15] & 0x80); + key(Keyboard::Z) = (bool)(state[0x2c] & 0x80); + + key(Keyboard::LeftBracket ) = (bool)(state[0x1a] & 0x80); + key(Keyboard::RightBracket) = (bool)(state[0x1b] & 0x80); + key(Keyboard::Backslash ) = (bool)(state[0x2b] & 0x80); + key(Keyboard::Semicolon ) = (bool)(state[0x27] & 0x80); + key(Keyboard::Apostrophe ) = (bool)(state[0x28] & 0x80); + key(Keyboard::Comma ) = (bool)(state[0x33] & 0x80); + key(Keyboard::Period ) = (bool)(state[0x34] & 0x80); + key(Keyboard::Slash ) = (bool)(state[0x35] & 0x80); + + key(Keyboard::Keypad1) = (bool)(state[0x4f] & 0x80); + key(Keyboard::Keypad2) = (bool)(state[0x50] & 0x80); + key(Keyboard::Keypad3) = (bool)(state[0x51] & 0x80); + key(Keyboard::Keypad4) = (bool)(state[0x4b] & 0x80); + key(Keyboard::Keypad5) = (bool)(state[0x4c] & 0x80); + key(Keyboard::Keypad6) = (bool)(state[0x4d] & 0x80); + key(Keyboard::Keypad7) = (bool)(state[0x47] & 0x80); + key(Keyboard::Keypad8) = (bool)(state[0x48] & 0x80); + key(Keyboard::Keypad9) = (bool)(state[0x49] & 0x80); + key(Keyboard::Keypad0) = (bool)(state[0x52] & 0x80); + key(Keyboard::Point ) = (bool)(state[0x53] & 0x80); + + key(Keyboard::Add ) = (bool)(state[0x4e] & 0x80); + key(Keyboard::Subtract) = (bool)(state[0x4a] & 0x80); + key(Keyboard::Multiply) = (bool)(state[0x37] & 0x80); + key(Keyboard::Divide ) = (bool)(state[0xb5] & 0x80); + key(Keyboard::Enter ) = (bool)(state[0x9c] & 0x80); + + key(Keyboard::NumLock ) = (bool)(state[0x45] & 0x80); + key(Keyboard::CapsLock) = (bool)(state[0x3a] & 0x80); + + key(Keyboard::Up ) = (bool)(state[0xc8] & 0x80); + key(Keyboard::Down ) = (bool)(state[0xd0] & 0x80); + key(Keyboard::Left ) = (bool)(state[0xcb] & 0x80); + key(Keyboard::Right) = (bool)(state[0xcd] & 0x80); + + key(Keyboard::Tab ) = (bool)(state[0x0f] & 0x80); + key(Keyboard::Return ) = (bool)(state[0x1c] & 0x80); + key(Keyboard::Spacebar) = (bool)(state[0x39] & 0x80); + key(Keyboard::Menu ) = (bool)(state[0xdd] & 0x80); + + key(Keyboard::Shift ) = (bool)(state[0x2a] & 0x80) || (bool)(state[0x36] & 0x80); + key(Keyboard::Control) = (bool)(state[0x1d] & 0x80) || (bool)(state[0x9d] & 0x80); + key(Keyboard::Alt ) = (bool)(state[0x38] & 0x80) || (bool)(state[0xb8] & 0x80); + key(Keyboard::Super ) = (bool)(state[0xdb] & 0x80) || (bool)(state[0xdc] & 0x80); + + #undef key + } + + //===== + //Mouse + //===== + + if(device.mouse) { + DIMOUSESTATE2 state; + if(FAILED(device.mouse->GetDeviceState(sizeof(DIMOUSESTATE2), (void*)&state))) { + device.mouse->Acquire(); + if(FAILED(device.mouse->GetDeviceState(sizeof(DIMOUSESTATE2), (void*)&state))) { + memset(&state, 0, sizeof(DIMOUSESTATE2)); + } + } + + table[mouse(0).axis(0)] = state.lX; + table[mouse(0).axis(1)] = state.lY; + table[mouse(0).axis(2)] = state.lZ / WHEEL_DELTA; + for(unsigned n = 0; n < Mouse::Buttons; n++) { + table[mouse(0).button(n)] = (bool)state.rgbButtons[n]; + } + + //on Windows, 0 = left, 1 = right, 2 = middle + //swap middle and right buttons for consistency with Linux + int16_t temp = table[mouse(0).button(1)]; + table[mouse(0).button(1)] = table[mouse(0).button(2)]; + table[mouse(0).button(2)] = temp; + } + + //========= + //Joypad(s) + //========= + + for(unsigned i = 0; i < Joypad::Count; i++) { + if(!device.gamepad[i]) continue; + + if(FAILED(device.gamepad[i]->Poll())) { + device.gamepad[i]->Acquire(); + continue; + } + + DIJOYSTATE2 state; + device.gamepad[i]->GetDeviceState(sizeof(DIJOYSTATE2), &state); + + //POV hats + for(unsigned n = 0; n < min((unsigned)Joypad::Hats, 4); n++) { + //POV value is in clockwise-hundredth degree units. + unsigned pov = state.rgdwPOV[n]; + //some drivers report a centered POV hat as -1U, others as 65535U. + //>= 36000 will match both, as well as invalid ranges. + if(pov < 36000) { + if(pov >= 31500 || pov <= 4500) table[joypad(i).hat(n)] |= Joypad::HatUp; + if(pov >= 4500 && pov <= 13500) table[joypad(i).hat(n)] |= Joypad::HatRight; + if(pov >= 13500 && pov <= 22500) table[joypad(i).hat(n)] |= Joypad::HatDown; + if(pov >= 22500 && pov <= 31500) table[joypad(i).hat(n)] |= Joypad::HatLeft; + } + } + + //axes + table[joypad(i).axis(0)] = state.lX; + table[joypad(i).axis(1)] = state.lY; + table[joypad(i).axis(2)] = state.lZ; + table[joypad(i).axis(3)] = state.lRx; + table[joypad(i).axis(4)] = state.lRy; + table[joypad(i).axis(5)] = state.lRz; + + //buttons + for(unsigned n = 0; n < min((unsigned)Joypad::Buttons, 128); n++) { + table[joypad(i).button(n)] = (bool)state.rgbButtons[n]; + } + } + + return true; + } + + bool init_joypad(const DIDEVICEINSTANCE *instance) { + unsigned n; + for(n = 0; n < Joypad::Count; n++) { if(!device.gamepad[n]) break; } + if(n >= Joypad::Count) return DIENUM_STOP; + + if(FAILED(device.context->CreateDevice(instance->guidInstance, &device.gamepad[n], 0))) { + return DIENUM_CONTINUE; //continue and try next gamepad + } + + device.gamepad[n]->SetDataFormat(&c_dfDIJoystick2); + device.gamepad[n]->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + device.gamepad[n]->EnumObjects(DI_EnumJoypadAxesCallback, (void*)this, DIDFT_ABSAXIS); + + return DIENUM_CONTINUE; + } + + bool init_axis(const DIDEVICEOBJECTINSTANCE *instance) { + signed n; + for(n = Joypad::Count - 1; n >= 0; n--) { if(device.gamepad[n]) break; } + if(n < 0) return DIENUM_STOP; + + DIPROPRANGE range; + range.diph.dwSize = sizeof(DIPROPRANGE); + range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + range.diph.dwHow = DIPH_BYID; + range.diph.dwObj = instance->dwType; + range.lMin = -32768; + range.lMax = +32767; + device.gamepad[n]->SetProperty(DIPROP_RANGE, &range.diph); + + return DIENUM_CONTINUE; + } + + bool init() { + device.context = 0; + device.keyboard = 0; + device.mouse = 0; + for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0; + device.mouseacquired = false; + + DirectInput8Create(GetModuleHandle(0), 0x0800, IID_IDirectInput8, (void**)&device.context, 0); + + device.context->CreateDevice(GUID_SysKeyboard, &device.keyboard, 0); + device.keyboard->SetDataFormat(&c_dfDIKeyboard); + device.keyboard->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + device.keyboard->Acquire(); + + device.context->CreateDevice(GUID_SysMouse, &device.mouse, 0); + device.mouse->SetDataFormat(&c_dfDIMouse2); + HRESULT hr = device.mouse->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + device.mouse->Acquire(); + + device.context->EnumDevices(DI8DEVCLASS_GAMECTRL, DI_EnumJoypadsCallback, (void*)this, DIEDFL_ATTACHEDONLY); + + return true; + } + + void term() { + if(device.keyboard) { + device.keyboard->Unacquire(); + device.keyboard->Release(); + device.keyboard = 0; + } + + if(device.mouse) { + device.mouse->Unacquire(); + device.mouse->Release(); + device.mouse = 0; + } + + for(unsigned i = 0; i < Joypad::Count; i++) { + if(device.gamepad[i]) { + device.gamepad[i]->Unacquire(); + device.gamepad[i]->Release(); + device.gamepad[i] = 0; + } + } + + if(device.context) { + device.context->Release(); + device.context = 0; + } + } + + bool acquire() { + if(!device.mouse) return false; + if(acquired() == false) { + device.mouse->Unacquire(); + device.mouse->SetCooperativeLevel(settings.handle, DISCL_EXCLUSIVE | DISCL_FOREGROUND); + device.mouse->Acquire(); + device.mouseacquired = true; + } + return true; + } + + bool unacquire() { + if(!device.mouse) return false; + if(acquired() == true) { + device.mouse->Unacquire(); + device.mouse->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + device.mouse->Acquire(); + device.mouseacquired = false; + } + return true; + } + + bool acquired() { + return device.mouseacquired; + } + + pInputDI() { + device.context = 0; + device.keyboard = 0; + device.mouse = 0; + for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0; + device.mouseacquired = false; + + settings.handle = 0; + } + + ~pInputDI() { term(); } +}; + +BOOL CALLBACK DI_EnumJoypadsCallback(const DIDEVICEINSTANCE *instance, void *p) { + return ((pInputDI*)p)->init_joypad(instance); +} + +BOOL CALLBACK DI_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE *instance, void *p) { + return ((pInputDI*)p)->init_axis(instance); +} + +DeclareInput(DI) + +}; diff --git a/ruby/input/rawinput.cpp b/ruby/input/rawinput.cpp new file mode 100755 index 00000000..c8789cc7 --- /dev/null +++ b/ruby/input/rawinput.cpp @@ -0,0 +1,807 @@ +//RawInput driver +//author: byuu + +//this driver utilizes RawInput (WM_INPUT) to capture keyboard and mouse input. +//although this requires WinXP or newer, it is the only way to uniquely identify +//and independently map multiple keyboards and mice. DirectInput merges all +//keyboards and mice into one device per. +// +//as WM_INPUT lacks specific RAWINPUT structures for gamepads, giving only raw +//data, and because DirectInput supports up to 16 joypads, DirectInput is used +//for joypad mapping. +// +//further, Xbox 360 controllers are explicitly detected and supported through +//XInput. this is because under DirectInput, the LT / RT (trigger) buttons are +//merged into a single Z-axis -- making it impossible to detect both buttons +//being pressed at the same time. with XInput, the state of both trigger +//buttons can be read independently. +// +//so in essence, this is actually more of a hybrid driver. + +#define DIRECTINPUT_VERSION 0x0800 +#include +#include + +namespace ruby { + +static DWORD WINAPI RawInputThreadProc(void*); +static LRESULT CALLBACK RawInputWindowProc(HWND, UINT, WPARAM, LPARAM); + +class RawInput { +public: + HANDLE mutex; + HWND hwnd; + bool initialized; + bool ready; + + struct Device { + HANDLE handle; + }; + + struct Keyboard : Device { + bool state[nall::Keyboard::Size]; + + void update(RAWINPUT *input) { + unsigned code = input->data.keyboard.MakeCode; + unsigned flags = input->data.keyboard.Flags; + + #define map(id, flag, name) if(code == id) state[name] = (bool)(flags == flag); + map(0x0001, 0, nall::Keyboard::Escape) + map(0x003b, 0, nall::Keyboard::F1) + map(0x003c, 0, nall::Keyboard::F2) + map(0x003d, 0, nall::Keyboard::F3) + map(0x003e, 0, nall::Keyboard::F4) + map(0x003f, 0, nall::Keyboard::F5) + map(0x0040, 0, nall::Keyboard::F6) + map(0x0041, 0, nall::Keyboard::F7) + map(0x0042, 0, nall::Keyboard::F8) + map(0x0043, 0, nall::Keyboard::F9) + map(0x0044, 0, nall::Keyboard::F10) + map(0x0057, 0, nall::Keyboard::F11) + map(0x0058, 0, nall::Keyboard::F12) + + map(0x0037, 2, nall::Keyboard::PrintScreen) + map(0x0046, 0, nall::Keyboard::ScrollLock) + map(0x001d, 4, nall::Keyboard::Pause) + map(0x0029, 0, nall::Keyboard::Tilde) + + map(0x0002, 0, nall::Keyboard::Num1) + map(0x0003, 0, nall::Keyboard::Num2) + map(0x0004, 0, nall::Keyboard::Num3) + map(0x0005, 0, nall::Keyboard::Num4) + map(0x0006, 0, nall::Keyboard::Num5) + map(0x0007, 0, nall::Keyboard::Num6) + map(0x0008, 0, nall::Keyboard::Num7) + map(0x0009, 0, nall::Keyboard::Num8) + map(0x000a, 0, nall::Keyboard::Num9) + map(0x000b, 0, nall::Keyboard::Num0) + + map(0x000c, 0, nall::Keyboard::Dash) + map(0x000d, 0, nall::Keyboard::Equal) + map(0x000e, 0, nall::Keyboard::Backspace) + + map(0x0052, 2, nall::Keyboard::Insert) + map(0x0053, 2, nall::Keyboard::Delete) + map(0x0047, 2, nall::Keyboard::Home) + map(0x004f, 2, nall::Keyboard::End) + map(0x0049, 2, nall::Keyboard::PageUp) + map(0x0051, 2, nall::Keyboard::PageDown) + + map(0x001e, 0, nall::Keyboard::A) + map(0x0030, 0, nall::Keyboard::B) + map(0x002e, 0, nall::Keyboard::C) + map(0x0020, 0, nall::Keyboard::D) + map(0x0012, 0, nall::Keyboard::E) + map(0x0021, 0, nall::Keyboard::F) + map(0x0022, 0, nall::Keyboard::G) + map(0x0023, 0, nall::Keyboard::H) + map(0x0017, 0, nall::Keyboard::I) + map(0x0024, 0, nall::Keyboard::J) + map(0x0025, 0, nall::Keyboard::K) + map(0x0026, 0, nall::Keyboard::L) + map(0x0032, 0, nall::Keyboard::M) + map(0x0031, 0, nall::Keyboard::N) + map(0x0018, 0, nall::Keyboard::O) + map(0x0019, 0, nall::Keyboard::P) + map(0x0010, 0, nall::Keyboard::Q) + map(0x0013, 0, nall::Keyboard::R) + map(0x001f, 0, nall::Keyboard::S) + map(0x0014, 0, nall::Keyboard::T) + map(0x0016, 0, nall::Keyboard::U) + map(0x002f, 0, nall::Keyboard::V) + map(0x0011, 0, nall::Keyboard::W) + map(0x002d, 0, nall::Keyboard::X) + map(0x0015, 0, nall::Keyboard::Y) + map(0x002c, 0, nall::Keyboard::Z) + + map(0x001a, 0, nall::Keyboard::LeftBracket) + map(0x001b, 0, nall::Keyboard::RightBracket) + map(0x002b, 0, nall::Keyboard::Backslash) + map(0x0027, 0, nall::Keyboard::Semicolon) + map(0x0028, 0, nall::Keyboard::Apostrophe) + map(0x0033, 0, nall::Keyboard::Comma) + map(0x0034, 0, nall::Keyboard::Period) + map(0x0035, 0, nall::Keyboard::Slash) + + map(0x004f, 0, nall::Keyboard::Keypad1) + map(0x0050, 0, nall::Keyboard::Keypad2) + map(0x0051, 0, nall::Keyboard::Keypad3) + map(0x004b, 0, nall::Keyboard::Keypad4) + map(0x004c, 0, nall::Keyboard::Keypad5) + map(0x004d, 0, nall::Keyboard::Keypad6) + map(0x0047, 0, nall::Keyboard::Keypad7) + map(0x0048, 0, nall::Keyboard::Keypad8) + map(0x0049, 0, nall::Keyboard::Keypad9) + map(0x0052, 0, nall::Keyboard::Keypad0) + + map(0x0053, 0, nall::Keyboard::Point) + map(0x001c, 2, nall::Keyboard::Enter) + map(0x004e, 0, nall::Keyboard::Add) + map(0x004a, 0, nall::Keyboard::Subtract) + map(0x0037, 0, nall::Keyboard::Multiply) + map(0x0035, 2, nall::Keyboard::Divide) + + map(0x0045, 0, nall::Keyboard::NumLock) + map(0x003a, 0, nall::Keyboard::CapsLock) + + //Pause signals 0x1d:4 + 0x45:0, whereas NumLock signals only 0x45:0. + //this makes it impractical to detect both Pause+NumLock independently. + //workaround: always detect Pause; detect NumLock only when Pause is released. + if(state[nall::Keyboard::Pause]) state[nall::Keyboard::NumLock] = false; + + map(0x0048, 2, nall::Keyboard::Up) + map(0x0050, 2, nall::Keyboard::Down) + map(0x004b, 2, nall::Keyboard::Left) + map(0x004d, 2, nall::Keyboard::Right) + + map(0x000f, 0, nall::Keyboard::Tab) + map(0x001c, 0, nall::Keyboard::Return) + map(0x0039, 0, nall::Keyboard::Spacebar) + map(0x005d, 2, nall::Keyboard::Menu) + + //merge left and right modifiers to one ID + if(code == 0x002a && flags == 0) state[nall::Keyboard::Shift] = 1; //left shift + if(code == 0x002a && flags == 1) state[nall::Keyboard::Shift] = 0; + if(code == 0x0036 && flags == 0) state[nall::Keyboard::Shift] = 1; //right shift + if(code == 0x0036 && flags == 1) state[nall::Keyboard::Shift] = 0; + + if(code == 0x001d && flags == 0) state[nall::Keyboard::Control] = 1; //left control + if(code == 0x001d && flags == 1) state[nall::Keyboard::Control] = 0; + if(code == 0x001d && flags == 2) state[nall::Keyboard::Control] = 1; //right control + if(code == 0x001d && flags == 3) state[nall::Keyboard::Control] = 0; + + if(code == 0x0038 && flags == 0) state[nall::Keyboard::Alt] = 1; //left alt + if(code == 0x0038 && flags == 1) state[nall::Keyboard::Alt] = 0; + if(code == 0x0038 && flags == 2) state[nall::Keyboard::Alt] = 1; //right alt + if(code == 0x0038 && flags == 3) state[nall::Keyboard::Alt] = 0; + + if(code == 0x005b && flags == 2) state[nall::Keyboard::Super] = 1; //left super + if(code == 0x005b && flags == 3) state[nall::Keyboard::Super] = 0; + if(code == 0x005c && flags == 2) state[nall::Keyboard::Super] = 1; //right super + if(code == 0x005c && flags == 3) state[nall::Keyboard::Super] = 0; + #undef map + } + + Keyboard() { + for(unsigned i = 0; i < nall::Keyboard::Size; i++) state[i] = false; + } + }; + + struct Mouse : Device { + signed xDistance; + signed yDistance; + signed zDistance; + unsigned buttonState; + + void sync() { + xDistance = 0; + yDistance = 0; + zDistance = 0; + } + + void update(RAWINPUT *input) { + if((input->data.mouse.usFlags & 1) == MOUSE_MOVE_RELATIVE) { + xDistance += input->data.mouse.lLastX; + yDistance += input->data.mouse.lLastY; + } + + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) buttonState |= 1 << 0; + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP ) buttonState &=~ 1 << 0; + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) buttonState |= 1 << 2; //swap middle and right buttons, + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP ) buttonState &=~ 1 << 2; //for consistency with Linux: + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) buttonState |= 1 << 1; //left = 0, middle = 1, right = 2 + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP ) buttonState &=~ 1 << 1; + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) buttonState |= 1 << 3; + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP ) buttonState &=~ 1 << 3; + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) buttonState |= 1 << 4; + if(input->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP ) buttonState &=~ 1 << 4; + + if(input->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) { + zDistance += (int16_t)input->data.mouse.usButtonData; + } + } + + Mouse() { + xDistance = yDistance = zDistance = 0; + buttonState = 0; + } + }; + + //keep track of gamepads for the sole purpose of distinguishing XInput devices + //from all other devices. this is necessary, as DirectInput does not provide + //a way to retrieve the necessary RIDI_DEVICENAME string. + struct Gamepad : Device { + bool isXInputDevice; + uint16_t vendorId; + uint16_t productId; + }; + + linear_vector lkeyboard; + linear_vector lmouse; + linear_vector lgamepad; + + LRESULT window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + if(msg == WM_INPUT) { + unsigned size = 0; + GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + RAWINPUT *input = new RAWINPUT[size]; + GetRawInputData((HRAWINPUT)lparam, RID_INPUT, input, &size, sizeof(RAWINPUTHEADER)); + WaitForSingleObject(mutex, INFINITE); + + if(input->header.dwType == RIM_TYPEKEYBOARD) { + for(unsigned i = 0; i < lkeyboard.size(); i++) { + if(input->header.hDevice == lkeyboard[i].handle) { + lkeyboard[i].update(input); + break; + } + } + } else if(input->header.dwType == RIM_TYPEMOUSE) { + for(unsigned i = 0; i < lmouse.size(); i++) { + if(input->header.hDevice == lmouse[i].handle) { + lmouse[i].update(input); + break; + } + } + } + + ReleaseMutex(mutex); + //allow propogation of WM_INPUT message + LRESULT result = DefRawInputProc(&input, size, sizeof(RAWINPUTHEADER)); + delete[] input; + return result; + } + + return DefWindowProc(hwnd, msg, wparam, lparam); + } + + //this is used to sort device IDs + struct DevicePool { + HANDLE handle; + wchar_t name[4096]; + bool operator<(const DevicePool &pool) const { return wcscmp(name, pool.name) < 0; } + }; + + int main() { + //create an invisible window to act as a sink, capturing all WM_INPUT messages + WNDCLASS wc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = (HBRUSH)COLOR_WINDOW; + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = RawInputWindowProc; + wc.lpszClassName = L"RawInputClass"; + wc.lpszMenuName = 0; + wc.style = CS_VREDRAW | CS_HREDRAW; + RegisterClass(&wc); + + hwnd = CreateWindow(L"RawInputClass", L"RawInputClass", WS_POPUP, + 0, 0, 64, 64, 0, 0, GetModuleHandle(0), 0); + + //enumerate all HID devices + unsigned devices = 0; + GetRawInputDeviceList(NULL, &devices, sizeof(RAWINPUTDEVICELIST)); + RAWINPUTDEVICELIST *list = new RAWINPUTDEVICELIST[devices]; + GetRawInputDeviceList(list, &devices, sizeof(RAWINPUTDEVICELIST)); + + //sort all devices by name. this has two important properties: + //1) it consistently orders peripherals, so mapped IDs remain constant + //2) it sorts the virtual keyboard and mouse to the bottom of the list + // (real devices start with \\?\HID#, virtual with \\?\Root#) + DevicePool pool[devices]; + for(unsigned i = 0; i < devices; i++) { + pool[i].handle = list[i].hDevice; + unsigned size = sizeof(pool[i].name) - 1; + GetRawInputDeviceInfo(list[i].hDevice, RIDI_DEVICENAME, &pool[i].name, &size); + } + nall::sort(pool, devices); + delete[] list; + + for(unsigned i = 0; i < devices; i++) { + RID_DEVICE_INFO info; + info.cbSize = sizeof(RID_DEVICE_INFO); + + unsigned size = info.cbSize; + GetRawInputDeviceInfo(pool[i].handle, RIDI_DEVICEINFO, &info, &size); + + if(info.dwType == RIM_TYPEKEYBOARD) { + unsigned n = lkeyboard.size(); + lkeyboard[n].handle = pool[i].handle; + } else if(info.dwType == RIM_TYPEMOUSE) { + unsigned n = lmouse.size(); + lmouse[n].handle = pool[i].handle; + } else if(info.dwType == RIM_TYPEHID) { + //if this is a gamepad or joystick device ... + if(info.hid.usUsagePage == 1 && (info.hid.usUsage == 4 || info.hid.usUsage == 5)) { + //... then cache device information for later use + unsigned n = lgamepad.size(); + lgamepad[n].handle = pool[i].handle; + lgamepad[n].vendorId = (uint16_t)info.hid.dwVendorId; + lgamepad[n].productId = (uint16_t)info.hid.dwProductId; + + //per MSDN: XInput devices have "IG_" in their device strings, + //which is how they should be identified. + string p = (const char*)utf8_t(pool[i].name); + if(auto position = strpos(p, "IG_")) { + lgamepad[n].isXInputDevice = true; + } else { + lgamepad[n].isXInputDevice = false; + } + } + } + } + + RAWINPUTDEVICE device[2]; + //capture all keyboard input + device[0].usUsagePage = 1; + device[0].usUsage = 6; + device[0].dwFlags = RIDEV_INPUTSINK; + device[0].hwndTarget = hwnd; + //capture all mouse input + device[1].usUsagePage = 1; + device[1].usUsage = 2; + device[1].dwFlags = RIDEV_INPUTSINK; + device[1].hwndTarget = hwnd; + RegisterRawInputDevices(device, 2, sizeof(RAWINPUTDEVICE)); + + WaitForSingleObject(mutex, INFINITE); + ready = true; + ReleaseMutex(mutex); + + while(true) { + MSG msg; + GetMessage(&msg, hwnd, 0, 0); + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; + } + + RawInput() : initialized(false), ready(false) { + } +}; + +static RawInput rawinput; + +DWORD WINAPI RawInputThreadProc(void*) { + return rawinput.main(); +} + +LRESULT CALLBACK RawInputWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + return rawinput.window_proc(hwnd, msg, wparam, lparam); +} + +class XInput { +public: + HMODULE libxinput; + DWORD WINAPI (*pXInputGetState)(DWORD, XINPUT_STATE*); + + struct Gamepad { + unsigned id; + + int16_t hat; + int16_t axis[6]; + bool button[10]; + + void poll(XINPUT_STATE &state) { + hat = Joypad::HatCenter; + if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hat |= Joypad::HatUp; + if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= Joypad::HatRight; + if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hat |= Joypad::HatDown; + if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hat |= Joypad::HatLeft; + + axis[0] = (int16_t)state.Gamepad.sThumbLX; + axis[1] = (int16_t)state.Gamepad.sThumbLY; + axis[2] = (int16_t)state.Gamepad.sThumbRX; + axis[3] = (int16_t)state.Gamepad.sThumbRY; + + //transform left and right trigger ranges: + //from: 0 (low, eg released) to 255 (high, eg pressed all the way down) + //to: +32767 (low) to -32768 (high) + uint16_t triggerX = state.Gamepad.bLeftTrigger; + uint16_t triggerY = state.Gamepad.bRightTrigger; + + triggerX = (triggerX << 8) | triggerX; + triggerY = (triggerY << 8) | triggerY; + + axis[4] = (~triggerX) - 32768; + axis[5] = (~triggerY) - 32768; + + button[0] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_A); + button[1] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_B); + button[2] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_X); + button[3] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_Y); + button[4] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK); + button[5] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_START); + button[6] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER); + button[7] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER); + button[8] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB); + button[9] = (bool)(state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB); + } + + Gamepad() { + hat = Joypad::HatCenter; + for(unsigned n = 0; n < 6; n++) axis[n] = 0; + for(unsigned n = 0; n < 10; n++) button[n] = false; + } + }; + + linear_vector lgamepad; + + void poll() { + if(!pXInputGetState) return; + + for(unsigned i = 0; i < lgamepad.size(); i++) { + XINPUT_STATE state; + DWORD result = pXInputGetState(lgamepad[i].id, &state); + if(result == ERROR_SUCCESS) lgamepad[i].poll(state); + } + } + + void init() { + if(!pXInputGetState) return; + + //XInput only supports up to four controllers + for(unsigned i = 0; i <= 3; i++) { + XINPUT_STATE state; + DWORD result = pXInputGetState(i, &state); + if(result == ERROR_SUCCESS) { + //valid controller detected, add to gamepad list + unsigned n = lgamepad.size(); + lgamepad[n].id = i; + } + } + } + + XInput() : pXInputGetState(0) { + //bind xinput1 dynamically, as it does not ship with Windows Vista or below + libxinput = LoadLibraryA("xinput1_3.dll"); + if(!libxinput) libxinput = LoadLibraryA("xinput1_2.dll"); + if(!libxinput) libxinput = LoadLibraryA("xinput1_1.dll"); + if(!libxinput) return; + pXInputGetState = (DWORD WINAPI (*)(DWORD, XINPUT_STATE*))GetProcAddress(libxinput, "XInputGetState"); + } + + ~XInput() { + if(libxinput) FreeLibrary(libxinput); + } +}; + +static BOOL CALLBACK DirectInput_EnumJoypadsCallback(const DIDEVICEINSTANCE*, void*); +static BOOL CALLBACK DirectInput_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE*, void*); + +class DirectInput { +public: + HWND handle; + LPDIRECTINPUT8 context; + struct Gamepad { + LPDIRECTINPUTDEVICE8 handle; + + int16_t hat[4]; + int16_t axis[6]; + bool button[128]; + + void poll(DIJOYSTATE2 &state) { + //POV hats + for(unsigned n = 0; n < 4; n++) { + hat[n] = Joypad::HatCenter; + + //POV value is in clockwise-hundredth degree units + unsigned pov = state.rgdwPOV[n]; + + //some drivers report a centered POV hat as -1U, others as 65535U. + //>= 36000 will match both, as well as invalid ranges. + if(pov >= 36000) continue; + + if(pov >= 31500 || pov <= 4500) hat[n] |= Joypad::HatUp; + if(pov >= 4500 && pov <= 13500) hat[n] |= Joypad::HatRight; + if(pov >= 13500 && pov <= 22500) hat[n] |= Joypad::HatDown; + if(pov >= 22500 && pov <= 31500) hat[n] |= Joypad::HatLeft; + } + + //axes + axis[0] = state.lX; + axis[1] = state.lY; + axis[2] = state.lZ; + axis[3] = state.lRx; + axis[4] = state.lRy; + axis[5] = state.lRz; + + //buttons + for(unsigned n = 0; n < 128; n++) { + button[n] = (bool)state.rgbButtons[n]; + } + } + + Gamepad() { + handle = 0; + for(unsigned n = 0; n < 4; n++) hat[n] = Joypad::HatCenter; + for(unsigned n = 0; n < 6; n++) axis[n] = 0; + for(unsigned n = 0; n < 128; n++) button[n] = false; + } + }; + linear_vector lgamepad; + + void poll() { + for(unsigned i = 0; i < lgamepad.size(); i++) { + if(FAILED(lgamepad[i].handle->Poll())) { + lgamepad[i].handle->Acquire(); + continue; + } + + DIJOYSTATE2 state; + lgamepad[i].handle->GetDeviceState(sizeof(DIJOYSTATE2), &state); + lgamepad[i].poll(state); + } + } + + bool init_joypad(const DIDEVICEINSTANCE *instance) { + //if this is an XInput device, do not acquire it via DirectInput ... + //the XInput driver above will handle said device. + for(unsigned i = 0; i < rawinput.lgamepad.size(); i++) { + uint32_t guid = MAKELONG(rawinput.lgamepad[i].vendorId, rawinput.lgamepad[i].productId); + if(guid == instance->guidProduct.Data1) { + if(rawinput.lgamepad[i].isXInputDevice == true) { + return DIENUM_CONTINUE; + } + } + } + + if(FAILED(context->CreateDevice(instance->guidInstance, &device, 0))) { + return DIENUM_CONTINUE; + } + + device->SetDataFormat(&c_dfDIJoystick2); + device->SetCooperativeLevel(handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + device->EnumObjects(DirectInput_EnumJoypadAxesCallback, (void*)this, DIDFT_ABSAXIS); + unsigned n = lgamepad.size(); + lgamepad[n].handle = device; + return DIENUM_CONTINUE; + } + + bool init_axis(const DIDEVICEOBJECTINSTANCE *instance) { + DIPROPRANGE range; + range.diph.dwSize = sizeof(DIPROPRANGE); + range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + range.diph.dwHow = DIPH_BYID; + range.diph.dwObj = instance->dwType; + range.lMin = -32768; + range.lMax = +32767; + device->SetProperty(DIPROP_RANGE, &range.diph); + return DIENUM_CONTINUE; + } + + void init(HWND handle_) { + handle = handle_; + DirectInput8Create(GetModuleHandle(0), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&context, 0); + context->EnumDevices(DI8DEVCLASS_GAMECTRL, DirectInput_EnumJoypadsCallback, (void*)this, DIEDFL_ATTACHEDONLY); + } + + void term() { + for(unsigned i = 0; i < lgamepad.size(); i++) { + lgamepad[i].handle->Unacquire(); + lgamepad[i].handle->Release(); + } + lgamepad.reset(); + + if(context) { + context->Release(); + context = 0; + } + } + +private: + LPDIRECTINPUTDEVICE8 device; +}; + +BOOL CALLBACK DirectInput_EnumJoypadsCallback(const DIDEVICEINSTANCE *instance, void *p) { + return ((DirectInput*)p)->init_joypad(instance); +} + +BOOL CALLBACK DirectInput_EnumJoypadAxesCallback(const DIDEVICEOBJECTINSTANCE *instance, void *p) { + return ((DirectInput*)p)->init_axis(instance); +} + +class pInputRaw { +public: + XInput xinput; + DirectInput dinput; + + bool acquire_mouse; + bool cursor_visible; + + struct { + HWND handle; + } settings; + + bool cap(const string& name) { + if(name == Input::Handle) return true; + if(name == Input::KeyboardSupport) return true; + if(name == Input::MouseSupport) return true; + if(name == Input::JoypadSupport) return true; + return false; + } + + any get(const string& name) { + if(name == Input::Handle) return (uintptr_t)settings.handle; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Input::Handle) { + settings.handle = (HWND)any_cast(value); + return true; + } + + return false; + } + + bool acquire() { + acquire_mouse = true; + if(cursor_visible == true) { + ShowCursor(cursor_visible = false); + } + return acquired(); + } + + bool unacquire() { + acquire_mouse = false; + ReleaseCapture(); + ClipCursor(NULL); + if(cursor_visible == false) { + ShowCursor(cursor_visible = true); + } + return true; + } + + bool acquired() { + if(acquire_mouse == true) { + SetFocus(settings.handle); + SetCapture(settings.handle); + RECT rc; + GetWindowRect(settings.handle, &rc); + ClipCursor(&rc); + } + return GetCapture() == settings.handle; + } + + bool poll(int16_t *table) { + memset(table, 0, Scancode::Limit * sizeof(int16_t)); + + WaitForSingleObject(rawinput.mutex, INFINITE); + + //========= + //Keyboards + //========= + for(unsigned i = 0; i < min(rawinput.lkeyboard.size(), (unsigned)Keyboard::Count); i++) { + for(unsigned n = 0; n < nall::Keyboard::Size; n++) { + //using keyboard(0)|= instead of keyboard(i)= merges all keyboards to KB0 + //this is done to favor ease of mapping over flexibility (eg share laptop+USB keyboard mapping) + table[keyboard(0).key(n)] |= rawinput.lkeyboard[i].state[n]; + } + } + + //==== + //Mice + //==== + for(unsigned i = 0; i < min(rawinput.lmouse.size(), (unsigned)Mouse::Count); i++) { + table[mouse(i).axis(0)] = rawinput.lmouse[i].xDistance; + table[mouse(i).axis(1)] = rawinput.lmouse[i].yDistance; + table[mouse(i).axis(2)] = rawinput.lmouse[i].zDistance; + + for(unsigned n = 0; n < min(5U, (unsigned)Mouse::Buttons); n++) { + table[mouse(i).button(n)] = (bool)(rawinput.lmouse[i].buttonState & (1 << n)); + } + + rawinput.lmouse[i].sync(); + } + + ReleaseMutex(rawinput.mutex); + + unsigned joy = 0; + + //================== + //XInput controllers + //================== + xinput.poll(); + for(unsigned i = 0; i < xinput.lgamepad.size(); i++) { + if(joy >= Joypad::Count) break; + + table[joypad(joy).hat(0)] = xinput.lgamepad[i].hat; + + for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) { + table[joypad(joy).axis(axis)] = xinput.lgamepad[i].axis[axis]; + } + + for(unsigned button = 0; button < min(10U, (unsigned)Joypad::Buttons); button++) { + table[joypad(joy).button(button)] = xinput.lgamepad[i].button[button]; + } + + joy++; + } + + //======================= + //DirectInput controllers + //======================= + dinput.poll(); + for(unsigned i = 0; i < dinput.lgamepad.size(); i++) { + if(joy >= Joypad::Count) break; + + for(unsigned hat = 0; hat < min(4U, (unsigned)Joypad::Hats); hat++) { + table[joypad(joy).hat(hat)] = dinput.lgamepad[i].hat[hat]; + } + + for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) { + table[joypad(joy).axis(axis)] = dinput.lgamepad[i].axis[axis]; + } + + for(unsigned button = 0; button < min(128U, (unsigned)Joypad::Buttons); button++) { + table[joypad(joy).button(button)] = dinput.lgamepad[i].button[button]; + } + + joy++; + } + + return true; + } + + bool init() { + //only spawn RawInput processing thread one time + if(rawinput.initialized == false) { + rawinput.initialized = true; + rawinput.mutex = CreateMutex(NULL, FALSE, NULL); + CreateThread(NULL, 0, RawInputThreadProc, 0, 0, NULL); + + //RawInput device calibration needs to finish before initializing DirectInput; + //as it needs device GUIDs to distinguish XInput devices from ordinary joypads. + bool ready = false; + do { + Sleep(10); + WaitForSingleObject(rawinput.mutex, INFINITE); + ready = rawinput.ready; + ReleaseMutex(rawinput.mutex); + } while(ready == false); + } + + xinput.init(); + dinput.init(settings.handle); + + acquire_mouse = false; + cursor_visible = true; + return true; + } + + void term() { + unacquire(); + dinput.term(); + } + + pInputRaw() { + } +}; + +DeclareInput(Raw) + +}; diff --git a/ruby/input/sdl.cpp b/ruby/input/sdl.cpp new file mode 100755 index 00000000..9a0db104 --- /dev/null +++ b/ruby/input/sdl.cpp @@ -0,0 +1,230 @@ +//================ +//SDL input driver +//================ +//Keyboard and mouse are controlled directly via Xlib, +//as SDL cannot capture input from windows it does not create itself. +//SDL is used only to handle joysticks / gamepads. + +#include +#include +#include + +namespace ruby { + +struct pInputSDL { + #include "xlibkeys.hpp" + + struct { + Display *display; + Window rootwindow; + Cursor InvisibleCursor; + SDL_Joystick *gamepad[Joypad::Count]; + + unsigned screenwidth, screenheight; + unsigned relativex, relativey; + bool mouseacquired; + + //mouse device settings + int accel_numerator; + int accel_denominator; + int threshold; + } device; + + struct { + uintptr_t handle; + } settings; + + bool cap(const string& name) { + if(name == Input::Handle) return true; + if(name == Input::KeyboardSupport) return true; + if(name == Input::MouseSupport) return true; + if(name == Input::JoypadSupport) return true; + return false; + } + + any get(const string& name) { + if(name == Input::Handle) return (uintptr_t)settings.handle; + return false; + } + + bool set(const string& name, const any &value) { + if(name == Input::Handle) { + settings.handle = any_cast(value); + return true; + } + + return false; + } + + bool acquire() { + if(acquired()) return true; + + if(XGrabPointer(device.display, settings.handle, True, 0, GrabModeAsync, GrabModeAsync, + device.rootwindow, device.InvisibleCursor, CurrentTime) == GrabSuccess) { + //backup existing cursor acceleration settings + XGetPointerControl(device.display, &device.accel_numerator, &device.accel_denominator, &device.threshold); + + //disable cursor acceleration + XChangePointerControl(device.display, True, False, 1, 1, 0); + + //center cursor (so that first relative poll returns 0, 0 if mouse has not moved) + XWarpPointer(device.display, None, device.rootwindow, 0, 0, 0, 0, device.screenwidth / 2, device.screenheight / 2); + + return device.mouseacquired = true; + } else { + return device.mouseacquired = false; + } + } + + bool unacquire() { + if(acquired()) { + //restore cursor acceleration and release cursor + XChangePointerControl(device.display, True, True, device.accel_numerator, device.accel_denominator, device.threshold); + XUngrabPointer(device.display, CurrentTime); + device.mouseacquired = false; + } + return true; + } + + bool acquired() { + return device.mouseacquired; + } + + bool poll(int16_t *table) { + memset(table, 0, Scancode::Limit * sizeof(int16_t)); + + //======== + //Keyboard + //======== + + x_poll(device.display, table); + + //===== + //Mouse + //===== + + Window root_return, child_return; + int root_x_return = 0, root_y_return = 0; + int win_x_return = 0, win_y_return = 0; + unsigned int mask_return = 0; + XQueryPointer(device.display, settings.handle, + &root_return, &child_return, &root_x_return, &root_y_return, + &win_x_return, &win_y_return, &mask_return); + + if(acquired()) { + XWindowAttributes attributes; + XGetWindowAttributes(device.display, settings.handle, &attributes); + + //absolute -> relative conversion + table[mouse(0).axis(0)] = (int16_t)(root_x_return - device.screenwidth / 2); + table[mouse(0).axis(1)] = (int16_t)(root_y_return - device.screenheight / 2); + + if(table[mouse(0).axis(0)] != 0 || table[mouse(0).axis(1)] != 0) { + //if mouse movement occurred, re-center mouse for next poll + XWarpPointer(device.display, None, device.rootwindow, 0, 0, 0, 0, device.screenwidth / 2, device.screenheight / 2); + } + } else { + table[mouse(0).axis(0)] = (int16_t)(root_x_return - device.relativex); + table[mouse(0).axis(1)] = (int16_t)(root_y_return - device.relativey); + + device.relativex = root_x_return; + device.relativey = root_y_return; + } + + //manual device polling is limited to only five buttons ... + table[mouse(0).button(0)] = (bool)(mask_return & Button1Mask); + table[mouse(0).button(1)] = (bool)(mask_return & Button2Mask); + table[mouse(0).button(2)] = (bool)(mask_return & Button3Mask); + table[mouse(0).button(3)] = (bool)(mask_return & Button4Mask); + table[mouse(0).button(4)] = (bool)(mask_return & Button5Mask); + + //========= + //Joypad(s) + //========= + + SDL_JoystickUpdate(); + for(unsigned i = 0; i < Joypad::Count; i++) { + if(!device.gamepad[i]) continue; + + //POV hats + unsigned hats = min((unsigned)Joypad::Hats, SDL_JoystickNumHats(device.gamepad[i])); + for(unsigned hat = 0; hat < hats; hat++) { + uint8_t state = SDL_JoystickGetHat(device.gamepad[i], hat); + if(state & SDL_HAT_UP ) table[joypad(i).hat(hat)] |= Joypad::HatUp; + if(state & SDL_HAT_RIGHT) table[joypad(i).hat(hat)] |= Joypad::HatRight; + if(state & SDL_HAT_DOWN ) table[joypad(i).hat(hat)] |= Joypad::HatDown; + if(state & SDL_HAT_LEFT ) table[joypad(i).hat(hat)] |= Joypad::HatLeft; + } + + //axes + unsigned axes = min((unsigned)Joypad::Axes, SDL_JoystickNumAxes(device.gamepad[i])); + for(unsigned axis = 0; axis < axes; axis++) { + table[joypad(i).axis(axis)] = (int16_t)SDL_JoystickGetAxis(device.gamepad[i], axis); + } + + //buttons + for(unsigned button = 0; button < Joypad::Buttons; button++) { + table[joypad(i).button(button)] = (bool)SDL_JoystickGetButton(device.gamepad[i], button); + } + } + + return true; + } + + bool init() { + SDL_InitSubSystem(SDL_INIT_JOYSTICK); + SDL_JoystickEventState(SDL_IGNORE); + + device.display = XOpenDisplay(0); + device.rootwindow = DefaultRootWindow(device.display); + XWindowAttributes attributes; + XGetWindowAttributes(device.display, device.rootwindow, &attributes); + device.screenwidth = attributes.width; + device.screenheight = attributes.height; + x_init(device.display); + + //Xlib: "because XShowCursor(false) would be too easy." + //create a fully transparent cursor named InvisibleCursor, + //for use while acquire() / XGrabPointer() is active. + Pixmap pixmap; + XColor black, unused; + static char invisible_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + Colormap colormap = DefaultColormap(device.display, DefaultScreen(device.display)); + XAllocNamedColor(device.display, colormap, "black", &black, &unused); + pixmap = XCreateBitmapFromData(device.display, settings.handle, invisible_data, 8, 8); + device.InvisibleCursor = XCreatePixmapCursor(device.display, pixmap, pixmap, &black, &black, 0, 0); + XFreePixmap(device.display, pixmap); + XFreeColors(device.display, colormap, &black.pixel, 1, 0); + + device.mouseacquired = false; + device.relativex = 0; + device.relativey = 0; + + unsigned joypads = min((unsigned)Joypad::Count, SDL_NumJoysticks()); + for(unsigned i = 0; i < joypads; i++) device.gamepad[i] = SDL_JoystickOpen(i); + + return true; + } + + void term() { + unacquire(); + XFreeCursor(device.display, device.InvisibleCursor); + + for(unsigned i = 0; i < Joypad::Count; i++) { + if(device.gamepad[i]) SDL_JoystickClose(device.gamepad[i]); + device.gamepad[i] = 0; + } + + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + XCloseDisplay(device.display); + } + + pInputSDL() { + for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0; + settings.handle = 0; + } +}; + +DeclareInput(SDL) + +}; diff --git a/ruby/input/x.cpp b/ruby/input/x.cpp new file mode 100755 index 00000000..7a1f7f39 --- /dev/null +++ b/ruby/input/x.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +namespace ruby { + +class pInputX { +public: + Display *display; + #include "xlibkeys.hpp" + + bool cap(const string& name) { + if(name == Input::KeyboardSupport) return true; + return false; + } + + any get(const string& name) { + return false; + } + + bool set(const string& name, const any &value) { + return false; + } + + bool acquire() { return false; } + bool unacquire() { return false; } + bool acquired() { return false; } + + bool poll(int16_t *table) { + memset(table, 0, Scancode::Limit * sizeof(int16_t)); + x_poll(display, table); + return true; + } + + bool init() { + display = XOpenDisplay(0); + x_init(display); + return true; + } + + void term() { + XCloseDisplay(display); + } +}; + +DeclareInput(X) + +}; diff --git a/ruby/input/xlibkeys.hpp b/ruby/input/xlibkeys.hpp new file mode 100755 index 00000000..70b70aaa --- /dev/null +++ b/ruby/input/xlibkeys.hpp @@ -0,0 +1,263 @@ +uint8_t scancode[256]; + +enum XScancode { + Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + ScrollLock, Pause, Tilde, + Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0, + Dash, Equal, Backspace, + Insert, Delete, Home, End, PageUp, PageDown, + A, B, C, D, E, F, G, H, I, J, K, L, M, + N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, + Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, + Point, Enter, Add, Subtract, Multiply, Divide, + Up, Down, Left, Right, + Tab, Return, Spacebar, Menu, + LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, LeftSuper, RightSuper, +}; + +void x_poll(Display *display, int16_t *table) { + if(!display) return; + + char state[32]; + XQueryKeymap(display, state); + + #define key(id) table[keyboard(0)[id]] + #define pressed(id) (bool)(state[scancode[id] >> 3] & (1 << (scancode[id] & 7))) + + key(Keyboard::Escape) = pressed(Escape); + + key(Keyboard::F1) = pressed(F1); + key(Keyboard::F2) = pressed(F2); + key(Keyboard::F3) = pressed(F3); + key(Keyboard::F4) = pressed(F4); + key(Keyboard::F5) = pressed(F5); + key(Keyboard::F6) = pressed(F6); + key(Keyboard::F7) = pressed(F7); + key(Keyboard::F8) = pressed(F8); + key(Keyboard::F9) = pressed(F9); + key(Keyboard::F10) = pressed(F10); + key(Keyboard::F11) = pressed(F11); + key(Keyboard::F12) = pressed(F12); + + key(Keyboard::ScrollLock) = pressed(ScrollLock); + key(Keyboard::Pause) = pressed(Pause); + key(Keyboard::Tilde) = pressed(Tilde); + + key(Keyboard::Num1) = pressed(Num1); + key(Keyboard::Num2) = pressed(Num2); + key(Keyboard::Num3) = pressed(Num3); + key(Keyboard::Num4) = pressed(Num4); + key(Keyboard::Num5) = pressed(Num5); + key(Keyboard::Num6) = pressed(Num6); + key(Keyboard::Num7) = pressed(Num7); + key(Keyboard::Num8) = pressed(Num8); + key(Keyboard::Num9) = pressed(Num9); + key(Keyboard::Num0) = pressed(Num0); + + key(Keyboard::Dash) = pressed(Dash); + key(Keyboard::Equal) = pressed(Equal); + key(Keyboard::Backspace) = pressed(Backspace); + + key(Keyboard::Insert) = pressed(Insert); + key(Keyboard::Delete) = pressed(Delete); + key(Keyboard::Home) = pressed(Home); + key(Keyboard::End) = pressed(End); + key(Keyboard::PageUp) = pressed(PageUp); + key(Keyboard::PageDown) = pressed(PageDown); + + key(Keyboard::A) = pressed(A); + key(Keyboard::B) = pressed(B); + key(Keyboard::C) = pressed(C); + key(Keyboard::D) = pressed(D); + key(Keyboard::E) = pressed(E); + key(Keyboard::F) = pressed(F); + key(Keyboard::G) = pressed(G); + key(Keyboard::H) = pressed(H); + key(Keyboard::I) = pressed(I); + key(Keyboard::J) = pressed(J); + key(Keyboard::K) = pressed(K); + key(Keyboard::L) = pressed(L); + key(Keyboard::M) = pressed(M); + key(Keyboard::N) = pressed(N); + key(Keyboard::O) = pressed(O); + key(Keyboard::P) = pressed(P); + key(Keyboard::Q) = pressed(Q); + key(Keyboard::R) = pressed(R); + key(Keyboard::S) = pressed(S); + key(Keyboard::T) = pressed(T); + key(Keyboard::U) = pressed(U); + key(Keyboard::V) = pressed(V); + key(Keyboard::W) = pressed(W); + key(Keyboard::X) = pressed(X); + key(Keyboard::Y) = pressed(Y); + key(Keyboard::Z) = pressed(Z); + + key(Keyboard::LeftBracket) = pressed(LeftBracket); + key(Keyboard::RightBracket) = pressed(RightBracket); + key(Keyboard::Backslash) = pressed(Backslash); + key(Keyboard::Semicolon) = pressed(Semicolon); + key(Keyboard::Apostrophe) = pressed(Apostrophe); + key(Keyboard::Comma) = pressed(Comma); + key(Keyboard::Period) = pressed(Period); + key(Keyboard::Slash) = pressed(Slash); + + key(Keyboard::Keypad1) = pressed(Keypad1); + key(Keyboard::Keypad2) = pressed(Keypad2); + key(Keyboard::Keypad3) = pressed(Keypad3); + key(Keyboard::Keypad4) = pressed(Keypad4); + key(Keyboard::Keypad5) = pressed(Keypad5); + key(Keyboard::Keypad6) = pressed(Keypad6); + key(Keyboard::Keypad7) = pressed(Keypad7); + key(Keyboard::Keypad8) = pressed(Keypad8); + key(Keyboard::Keypad9) = pressed(Keypad9); + key(Keyboard::Keypad0) = pressed(Keypad0); + + key(Keyboard::Point) = pressed(Point); + key(Keyboard::Enter) = pressed(Enter); + key(Keyboard::Add) = pressed(Add); + key(Keyboard::Subtract) = pressed(Subtract); + key(Keyboard::Multiply) = pressed(Multiply); + key(Keyboard::Divide) = pressed(Divide); + + key(Keyboard::Up) = pressed(Up); + key(Keyboard::Down) = pressed(Down); + key(Keyboard::Left) = pressed(Left); + key(Keyboard::Right) = pressed(Right); + + key(Keyboard::Tab) = pressed(Tab); + key(Keyboard::Return) = pressed(Return); + key(Keyboard::Spacebar) = pressed(Spacebar); + key(Keyboard::Menu) = pressed(Menu); + + key(Keyboard::Shift) = pressed(LeftShift) || pressed(RightShift); + key(Keyboard::Control) = pressed(LeftControl) || pressed(RightControl); + key(Keyboard::Alt) = pressed(LeftAlt) || pressed(RightAlt); + key(Keyboard::Super) = pressed(LeftSuper) || pressed(RightSuper); + + #undef key + #undef pressed +} + +void x_init(Display *display) { + if(!display) return; + + memset(&scancode, 0, sizeof scancode); + + #define assign(x, y) scancode[x] = XKeysymToKeycode(display, y) + assign(Escape, XK_Escape); + + assign(F1, XK_F1); + assign(F2, XK_F2); + assign(F3, XK_F3); + assign(F4, XK_F4); + assign(F5, XK_F5); + assign(F6, XK_F6); + assign(F7, XK_F7); + assign(F8, XK_F8); + assign(F9, XK_F9); + assign(F10, XK_F10); + assign(F11, XK_F11); + assign(F12, XK_F12); + + assign(ScrollLock, XK_Scroll_Lock); + assign(Pause, XK_Pause); + + assign(Tilde, XK_asciitilde); + + assign(Num0, XK_0); + assign(Num1, XK_1); + assign(Num2, XK_2); + assign(Num3, XK_3); + assign(Num4, XK_4); + assign(Num5, XK_5); + assign(Num6, XK_6); + assign(Num7, XK_7); + assign(Num8, XK_8); + assign(Num9, XK_9); + + assign(Dash, XK_minus); + assign(Equal, XK_equal); + assign(Backspace, XK_BackSpace); + + assign(Insert, XK_Insert); + assign(Delete, XK_Delete); + assign(Home, XK_Home); + assign(End, XK_End); + assign(PageUp, XK_Prior); + assign(PageDown, XK_Next); + + assign(A, XK_A); + assign(B, XK_B); + assign(C, XK_C); + assign(D, XK_D); + assign(E, XK_E); + assign(F, XK_F); + assign(G, XK_G); + assign(H, XK_H); + assign(I, XK_I); + assign(J, XK_J); + assign(K, XK_K); + assign(L, XK_L); + assign(M, XK_M); + assign(N, XK_N); + assign(O, XK_O); + assign(P, XK_P); + assign(Q, XK_Q); + assign(R, XK_R); + assign(S, XK_S); + assign(T, XK_T); + assign(U, XK_U); + assign(V, XK_V); + assign(W, XK_W); + assign(X, XK_X); + assign(Y, XK_Y); + assign(Z, XK_Z); + + assign(LeftBracket, XK_bracketleft); + assign(RightBracket, XK_bracketright); + assign(Backslash, XK_backslash); + assign(Semicolon, XK_semicolon); + assign(Apostrophe, XK_apostrophe); + assign(Comma, XK_comma); + assign(Period, XK_period); + assign(Slash, XK_slash); + + assign(Keypad0, XK_KP_0); + assign(Keypad1, XK_KP_1); + assign(Keypad2, XK_KP_2); + assign(Keypad3, XK_KP_3); + assign(Keypad4, XK_KP_4); + assign(Keypad5, XK_KP_5); + assign(Keypad6, XK_KP_6); + assign(Keypad7, XK_KP_7); + assign(Keypad8, XK_KP_8); + assign(Keypad9, XK_KP_9); + + assign(Add, XK_KP_Add); + assign(Subtract, XK_KP_Subtract); + assign(Multiply, XK_KP_Multiply); + assign(Divide, XK_KP_Divide); + assign(Enter, XK_KP_Enter); + + assign(Up, XK_Up); + assign(Down, XK_Down); + assign(Left, XK_Left); + assign(Right, XK_Right); + + assign(Tab, XK_Tab); + assign(Return, XK_Return); + assign(Spacebar, XK_space); + + assign(LeftControl, XK_Control_L); + assign(RightControl, XK_Control_R); + assign(LeftAlt, XK_Alt_L); + assign(RightAlt, XK_Alt_R); + assign(LeftShift, XK_Shift_L); + assign(RightShift, XK_Shift_R); + assign(LeftSuper, XK_Super_L); + assign(RightSuper, XK_Super_R); + assign(Menu, XK_Menu); + + #undef assign +} diff --git a/ruby/ruby.cpp b/ruby/ruby.cpp new file mode 100755 index 00000000..1a002006 --- /dev/null +++ b/ruby/ruby.cpp @@ -0,0 +1,405 @@ +#include + +#undef mkdir +#undef usleep +#include + +namespace ruby { + +VideoInterface video; +AudioInterface audio; +InputInterface input; + +/* VideoInterface */ + +const char *Video::Handle = "Handle"; +const char *Video::Synchronize = "Synchronize"; +const char *Video::Filter = "Filter"; +const char *Video::Shader = "Shader"; +const char *Video::FragmentShader = "FragmentShader"; +const char *Video::VertexShader = "VertexShader"; + +void VideoInterface::driver(const char *driver) { + if(p) term(); + + if(!driver || !*driver) driver = default_driver(); + + if(0); + + #ifdef VIDEO_DIRECT3D + else if(!strcmp(driver, "Direct3D")) p = new VideoD3D(); + #endif + + #ifdef VIDEO_DIRECTDRAW + else if(!strcmp(driver, "DirectDraw")) p = new VideoDD(); + #endif + + #ifdef VIDEO_GDI + else if(!strcmp(driver, "GDI")) p = new VideoGDI(); + #endif + + #ifdef VIDEO_GLX + else if(!strcmp(driver, "OpenGL")) p = new VideoGLX(); + #endif + + #ifdef VIDEO_QTOPENGL + else if(!strcmp(driver, "Qt-OpenGL")) p = new VideoQtOpenGL(); + #endif + + #ifdef VIDEO_QTRASTER + else if(!strcmp(driver, "Qt-Raster")) p = new VideoQtRaster(); + #endif + + #ifdef VIDEO_SDL + else if(!strcmp(driver, "SDL")) p = new VideoSDL(); + #endif + + #ifdef VIDEO_WGL + else if(!strcmp(driver, "OpenGL")) p = new VideoWGL(); + #endif + + #ifdef VIDEO_XV + else if(!strcmp(driver, "X-Video")) p = new VideoXv(); + #endif + + else p = new Video(); +} + +//select the *safest* available driver, not the fastest +const char* VideoInterface::default_driver() { + #if defined(VIDEO_DIRECT3D) + return "Direct3D"; + #elif defined(VIDEO_WGL) + return "OpenGL"; + #elif defined(VIDEO_DIRECTDRAW) + return "DirectDraw"; + #elif defined(VIDEO_GDI) + return "GDI"; + #elif defined(VIDEO_QTOPENGL) + return "Qt-OpenGL"; + #elif defined(VIDEO_QTRASTER) + return "Qt-Raster"; + #elif defined(VIDEO_SDL) + return "SDL"; + #elif defined(VIDEO_XV) + return "X-Video"; + #elif defined(VIDEO_GLX) + return "OpenGL"; + #else + return "None"; + #endif +} + +//returns list of available drivers, sorted from most to least optimal +const char* VideoInterface::driver_list() { + return + + //Windows + + #if defined(VIDEO_DIRECT3D) + "Direct3D;" + #endif + + #if defined(VIDEO_WGL) + "OpenGL;" + #endif + + #if defined(VIDEO_DIRECTDRAW) + "DirectDraw;" + #endif + + #if defined(VIDEO_GDI) + "GDI;" + #endif + + //Linux + + #if defined(VIDEO_GLX) + "OpenGL;" + #endif + + #if defined(VIDEO_QTOPENGL) + "Qt-OpenGL;" + #endif + + #if defined(VIDEO_XV) + "X-Video;" + #endif + + #if defined(VIDEO_QTRASTER) + "Qt-Raster;" + #endif + + #if defined(VIDEO_SDL) + "SDL;" + #endif + + "None"; +} + +bool VideoInterface::init() { + if(!p) driver(); + return p->init(); +} + +void VideoInterface::term() { + if(p) { + delete p; + p = nullptr; + } +} + +bool VideoInterface::cap(const string& name) { return p ? p->cap(name) : false; } +any VideoInterface::get(const string& name) { return p ? p->get(name) : false; } +bool VideoInterface::set(const string& name, const any& value) { return p ? p->set(name, value) : false; } +bool VideoInterface::lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { return p ? p->lock(data, pitch, width, height) : false; } +void VideoInterface::unlock() { if(p) p->unlock(); } +void VideoInterface::clear() { if(p) p->clear(); } +void VideoInterface::refresh() { if(p) p->refresh(); } +VideoInterface::VideoInterface() : p(nullptr) {} +VideoInterface::~VideoInterface() { term(); } + +/* AudioInterface */ + +const char *Audio::Handle = "Handle"; +const char *Audio::Synchronize = "Synchronize"; +const char *Audio::Frequency = "Frequency"; +const char *Audio::Latency = "Latency"; + +void AudioInterface::driver(const char *driver) { + if(p) term(); + + if(!driver || !*driver) driver = default_driver(); + + if(0); + + #ifdef AUDIO_ALSA + else if(!strcmp(driver, "ALSA")) p = new AudioALSA(); + #endif + + #ifdef AUDIO_AO + else if(!strcmp(driver, "libao")) p = new AudioAO(); + #endif + + #ifdef AUDIO_DIRECTSOUND + else if(!strcmp(driver, "DirectSound")) p = new AudioDS(); + #endif + + #ifdef AUDIO_OPENAL + else if(!strcmp(driver, "OpenAL")) p = new AudioOpenAL(); + #endif + + #ifdef AUDIO_OSS + else if(!strcmp(driver, "OSS")) p = new AudioOSS(); + #endif + + #ifdef AUDIO_PULSEAUDIO + else if(!strcmp(driver, "PulseAudio")) p = new AudioPulseAudio(); + #endif + + #ifdef AUDIO_PULSEAUDIOSIMPLE + else if(!strcmp(driver, "PulseAudioSimple")) p = new AudioPulseAudioSimple(); + #endif + + #ifdef AUDIO_XAUDIO2 + else if(!strcmp(driver, "XAudio2")) p = new AudioXAudio2(); + #endif + + else p = new Audio(); +} + +//select the *safest* available driver, not the fastest +const char* AudioInterface::default_driver() { + #if defined(AUDIO_DIRECTSOUND) + return "DirectSound"; + #elif defined(AUDIO_XAUDIO2) + return "XAudio2"; + #elif defined(AUDIO_ALSA) + return "ALSA"; + #elif defined(AUDIO_OPENAL) + return "OpenAL"; + #elif defined(AUDIO_PULSEAUDIO) + return "PulseAudio"; + #elif defined(AUDIO_PULSEAUDIOSIMPLE) + return "PulseAudioSimple"; + #elif defined(AUDIO_AO) + return "libao"; + #elif defined(AUDIO_OSS) + return "OSS"; + #else + return "None"; + #endif +} + +//returns list of available drivers, sorted from most to least optimal +const char* AudioInterface::driver_list() { + return + + //Windows + + #if defined(AUDIO_DIRECTSOUND) + "DirectSound;" + #endif + + #if defined(AUDIO_XAUDIO2) + "XAudio2;" + #endif + + //Linux + + #if defined(AUDIO_ALSA) + "ALSA;" + #endif + + #if defined(AUDIO_OPENAL) + "OpenAL;" + #endif + + #if defined(AUDIO_OSS) + "OSS;" + #endif + + #if defined(AUDIO_PULSEAUDIO) + "PulseAudio;" + #endif + + #if defined(AUDIO_PULSEAUDIOSIMPLE) + "PulseAudioSimple;" + #endif + + #if defined(AUDIO_AO) + "libao;" + #endif + + "None"; +} + +bool AudioInterface::init() { + if(!p) driver(); + return p->init(); +} + +void AudioInterface::term() { + if(p) { + delete p; + p = nullptr; + } +} + +bool AudioInterface::cap(const string& name) { return p ? p->cap(name) : false; } +any AudioInterface::get(const string& name) { return p ? p->get(name) : false; } +bool AudioInterface::set(const string& name, const any& value) { return p ? p->set(name, value) : false; } +void AudioInterface::sample(uint16_t left, uint16_t right) { if(p) p->sample(left, right); } +void AudioInterface::clear() { if(p) p->clear(); } +AudioInterface::AudioInterface() : p(nullptr) {} +AudioInterface::~AudioInterface() { term(); } + +/* InputInterface */ + +const char *Input::Handle = "Handle"; +const char *Input::KeyboardSupport = "KeyboardSupport"; +const char *Input::MouseSupport = "MouseSupport"; +const char *Input::JoypadSupport = "JoypadSupport"; + +void InputInterface::driver(const char *driver) { + if(p) term(); + + if(!driver || !*driver) driver = default_driver(); + + if(0); + + #ifdef INPUT_DIRECTINPUT + else if(!strcmp(driver, "DirectInput")) p = new InputDI(); + #endif + + #ifdef INPUT_RAWINPUT + else if(!strcmp(driver, "RawInput")) p = new InputRaw(); + #endif + + #ifdef INPUT_SDL + else if(!strcmp(driver, "SDL")) p = new InputSDL(); + #endif + + #ifdef INPUT_X + else if(!strcmp(driver, "X-Windows")) p = new InputX(); + #endif + + #ifdef INPUT_CARBON + else if(!strcmp(driver, "Carbon")) p = new InputCarbon(); + #endif + + else p = new Input(); +} + +//select the *safest* available driver, not the fastest +const char* InputInterface::default_driver() { + #if defined(INPUT_RAWINPUT) + return "RawInput"; + #elif defined(INPUT_DIRECTINPUT) + return "DirectInput"; + #elif defined(INPUT_SDL) + return "SDL"; + #elif defined(INPUT_X) + return "X-Windows"; + #elif defined(INPUT_CARBON) + return "Carbon"; + #else + return "none"; + #endif +} + +const char* InputInterface::driver_list() { + return + + //Windows + + #if defined(INPUT_RAWINPUT) + "RawInput;" + #endif + + #if defined(INPUT_DIRECTINPUT) + "DirectInput;" + #endif + + //Linux + + #if defined(INPUT_SDL) + "SDL;" + #endif + + #if defined(INPUT_X) + "X-Windows;" + #endif + + //OS X + + #if defined(INPUT_CARBON) + "Carbon;" + #endif + + "None"; +} + +bool InputInterface::init() { + if(!p) driver(); + return p->init(); +} + +void InputInterface::term() { + if(p) { + delete p; + p = nullptr; + } +} + +bool InputInterface::cap(const string& name) { return p ? p->cap(name) : false; } +any InputInterface::get(const string& name) { return p ? p->get(name) : false; } +bool InputInterface::set(const string& name, const any& value) { return p ? p->set(name, value) : false; } +bool InputInterface::acquire() { return p ? p->acquire() : false; } +bool InputInterface::unacquire() { return p ? p->unacquire() : false; } +bool InputInterface::acquired() { return p ? p->acquired() : false; } +bool InputInterface::poll(int16_t *table) { return p ? p->poll(table) : false; } +InputInterface::InputInterface() : p(nullptr) {} +InputInterface::~InputInterface() { term(); } + +}; diff --git a/ruby/ruby.hpp b/ruby/ruby.hpp new file mode 100755 index 00000000..a8b08227 --- /dev/null +++ b/ruby/ruby.hpp @@ -0,0 +1,98 @@ +/* + ruby + version: 0.07 (2011-08-14) + license: public domain +*/ + +#ifndef RUBY_H +#define RUBY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ruby { + +#include +#include +#include + +struct VideoInterface { + void driver(const char *driver = ""); + const char* default_driver(); + const char* driver_list(); + bool init(); + void term(); + + bool cap(const nall::string& name); + nall::any get(const nall::string& name); + bool set(const nall::string& name, const nall::any& value); + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height); + void unlock(); + void clear(); + void refresh(); + VideoInterface(); + ~VideoInterface(); + +private: + Video *p; +}; + +struct AudioInterface { + void driver(const char *driver = ""); + const char* default_driver(); + const char* driver_list(); + bool init(); + void term(); + + bool cap(const nall::string& name); + nall::any get(const nall::string& name); + bool set(const nall::string& name, const nall::any& value); + + void sample(uint16_t left, uint16_t right); + void clear(); + AudioInterface(); + ~AudioInterface(); + +private: + Audio *p; +}; + +struct InputInterface { + void driver(const char *driver = ""); + const char* default_driver(); + const char* driver_list(); + bool init(); + void term(); + + bool cap(const nall::string& name); + nall::any get(const nall::string& name); + bool set(const nall::string& name, const nall::any& value); + + bool acquire(); + bool unacquire(); + bool acquired(); + + bool poll(int16_t *table); + InputInterface(); + ~InputInterface(); + +private: + Input *p; +}; + +extern VideoInterface video; +extern AudioInterface audio; +extern InputInterface input; + +}; + +#endif diff --git a/ruby/ruby_impl.cpp b/ruby/ruby_impl.cpp new file mode 100755 index 00000000..aca0e7af --- /dev/null +++ b/ruby/ruby_impl.cpp @@ -0,0 +1,184 @@ +/* Global Headers */ + +#if defined(VIDEO_QTOPENGL) || defined(VIDEO_QTRASTER) + #include + #include +#endif + +#if defined(VIDEO_QTOPENGL) + #include + #if defined(PLATFORM_WINDOWS) + #include + #endif +#endif + +#if defined(PLATFORM_X) + #include + #include + #include +#elif defined(PLATFORM_OSX) + #define __INTEL_COMPILER + #include +#elif defined(PLATFORM_WINDOWS) + #define _WIN32_WINNT 0x0501 + #include +#endif + +using namespace nall; + +/* Video */ + +#define DeclareVideo(Name) \ + class Video##Name : public Video { \ + public: \ + bool cap(const string& name) { return p.cap(name); } \ + any get(const string& name) { return p.get(name); } \ + bool set(const string& name, const any& value) { return p.set(name, value); } \ + \ + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { return p.lock(data, pitch, width, height); } \ + void unlock() { p.unlock(); } \ + \ + void clear() { p.clear(); } \ + void refresh() { p.refresh(); } \ + bool init() { return p.init(); } \ + void term() { p.term(); } \ + \ + Video##Name() : p(*new pVideo##Name) {} \ + ~Video##Name() { delete &p; } \ + \ + private: \ + pVideo##Name &p; \ + }; + +#ifdef VIDEO_DIRECT3D + #include +#endif + +#ifdef VIDEO_DIRECTDRAW + #include +#endif + +#ifdef VIDEO_GDI + #include +#endif + +#ifdef VIDEO_GLX + #include +#endif + +#ifdef VIDEO_QTOPENGL + #include +#endif + +#ifdef VIDEO_QTRASTER + #include +#endif + +#ifdef VIDEO_SDL + #include +#endif + +#ifdef VIDEO_WGL + #include +#endif + +#ifdef VIDEO_XV + #include +#endif + +/* Audio */ + +#define DeclareAudio(Name) \ + class Audio##Name : public Audio { \ + public: \ + bool cap(const string& name) { return p.cap(name); } \ + any get(const string& name) { return p.get(name); } \ + bool set(const string& name, const any& value) { return p.set(name, value); } \ + \ + void sample(uint16_t left, uint16_t right) { p.sample(left, right); } \ + void clear() { p.clear(); } \ + bool init() { return p.init(); } \ + void term() { p.term(); } \ + \ + Audio##Name() : p(*new pAudio##Name) {} \ + ~Audio##Name() { delete &p; } \ + \ + private: \ + pAudio##Name &p; \ + }; + +#ifdef AUDIO_ALSA + #include +#endif + +#ifdef AUDIO_AO + #include +#endif + +#ifdef AUDIO_DIRECTSOUND + #include +#endif + +#ifdef AUDIO_OPENAL + #include +#endif + +#ifdef AUDIO_OSS + #include +#endif + +#ifdef AUDIO_PULSEAUDIO + #include +#endif + +#ifdef AUDIO_PULSEAUDIOSIMPLE + #include +#endif + +#ifdef AUDIO_XAUDIO2 + #include +#endif + +/* Input */ + +#define DeclareInput(Name) \ + class Input##Name : public Input { \ + public: \ + bool cap(const string& name) { return p.cap(name); } \ + any get(const string& name) { return p.get(name); } \ + bool set(const string& name, const any& value) { return p.set(name, value); } \ + \ + bool acquire() { return p.acquire(); } \ + bool unacquire() { return p.unacquire(); } \ + bool acquired() { return p.acquired(); } \ + \ + bool poll(int16_t *table) { return p.poll(table); } \ + bool init() { return p.init(); } \ + void term() { p.term(); } \ + \ + Input##Name() : p(*new pInput##Name) {} \ + ~Input##Name() { delete &p; } \ + \ + private: \ + pInput##Name &p; \ + }; + +#ifdef INPUT_DIRECTINPUT + #include +#endif + +#ifdef INPUT_RAWINPUT + #include +#endif + +#ifdef INPUT_SDL + #include +#endif + +#ifdef INPUT_X + #include +#endif + +#ifdef INPUT_CARBON + #include +#endif diff --git a/ruby/video.hpp b/ruby/video.hpp new file mode 100755 index 00000000..c79c5531 --- /dev/null +++ b/ruby/video.hpp @@ -0,0 +1,29 @@ +class Video { +public: + static const char *Handle; + static const char *Synchronize; + static const char *Filter; + static const char *Shader; + static const char *FragmentShader; + static const char *VertexShader; + + enum Filter { + FilterPoint, + FilterLinear, + }; + + virtual bool cap(const nall::string& name) { return false; } + virtual nall::any get(const nall::string& name) { return false; } + virtual bool set(const nall::string& name, const nall::any& value) { return false; } + + virtual bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { return false; } + virtual void unlock() {} + + virtual void clear() {} + virtual void refresh() {} + virtual bool init() { return true; } + virtual void term() {} + + Video() {} + virtual ~Video() {} +}; diff --git a/ruby/video/direct3d.cpp b/ruby/video/direct3d.cpp new file mode 100755 index 00000000..f4bdd599 --- /dev/null +++ b/ruby/video/direct3d.cpp @@ -0,0 +1,457 @@ +#undef interface +#define interface struct +#include +#include +#undef interface + +#define D3DVERTEX (D3DFVF_XYZRHW | D3DFVF_TEX1) + +typedef HRESULT (__stdcall *EffectProc)(LPDIRECT3DDEVICE9, LPCVOID, UINT, D3DXMACRO const*, LPD3DXINCLUDE, DWORD, LPD3DXEFFECTPOOL, LPD3DXEFFECT*, LPD3DXBUFFER*); +typedef HRESULT (__stdcall *TextureProc)(LPDIRECT3DDEVICE9, LPCTSTR, LPDIRECT3DTEXTURE9*); + +namespace ruby { + +class pVideoD3D { +public: + LPDIRECT3D9 lpd3d; + LPDIRECT3DDEVICE9 device; + LPDIRECT3DVERTEXBUFFER9 vertex_buffer, *vertex_ptr; + D3DPRESENT_PARAMETERS presentation; + D3DSURFACE_DESC d3dsd; + D3DLOCKED_RECT d3dlr; + D3DRASTER_STATUS d3drs; + D3DCAPS9 d3dcaps; + LPDIRECT3DTEXTURE9 texture; + LPDIRECT3DSURFACE9 surface; + LPD3DXEFFECT effect; + string shader_source_markup; + + bool lost; + unsigned iwidth, iheight; + + struct d3dvertex { + float x, y, z, rhw; //screen coords + float u, v; //texture coords + }; + + struct { + uint32_t t_usage, v_usage; + uint32_t t_pool, v_pool; + uint32_t lock; + uint32_t filter; + } flags; + + struct { + bool dynamic; //device supports dynamic textures + bool shader; //device supports pixel shaders + } caps; + + struct { + HWND handle; + bool synchronize; + unsigned filter; + + unsigned width; + unsigned height; + } settings; + + struct { + unsigned width; + unsigned height; + } state; + + bool cap(const string& name) { + if(name == Video::Handle) return true; + if(name == Video::Synchronize) return true; + if(name == Video::Filter) return true; + if(name == Video::Shader) return true; + return false; + } + + any get(const string& name) { + if(name == Video::Handle) return (uintptr_t)settings.handle; + if(name == Video::Synchronize) return settings.synchronize; + if(name == Video::Filter) return settings.filter; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Handle) { + settings.handle = (HWND)any_cast(value); + return true; + } + + if(name == Video::Synchronize) { + settings.synchronize = any_cast(value); + return true; + } + + if(name == Video::Filter) { + settings.filter = any_cast(value); + if(lpd3d) update_filter(); + return true; + } + + if(name == Video::Shader) { + set_shader(any_cast(value)); + return true; + } + + return false; + } + + bool recover() { + if(!device) return false; + + if(lost) { + release_resources(); + if(device->Reset(&presentation) != D3D_OK) return false; + } + + lost = false; + + device->SetDialogBoxMode(false); + + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + device->SetRenderState(D3DRS_LIGHTING, false); + device->SetRenderState(D3DRS_ZENABLE, false); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); + + device->SetVertexShader(NULL); + device->SetFVF(D3DVERTEX); + + device->CreateVertexBuffer(sizeof(d3dvertex) * 4, flags.v_usage, D3DVERTEX, (D3DPOOL)flags.v_pool, &vertex_buffer, NULL); + iwidth = 0; + iheight = 0; + resize(settings.width = 256, settings.height = 256); + update_filter(); + clear(); + return true; + } + + unsigned rounded_power_of_two(unsigned n) { + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + return n + 1; + } + + void resize(unsigned width, unsigned height) { + if(iwidth >= width && iheight >= height) return; + + iwidth = rounded_power_of_two(max(width, iwidth )); + iheight = rounded_power_of_two(max(height, iheight)); + + if(d3dcaps.MaxTextureWidth < iwidth || d3dcaps.MaxTextureWidth < iheight) { + //TODO: attempt to handle this more gracefully + return; + } + + if(texture) texture->Release(); + device->CreateTexture(iwidth, iheight, 1, flags.t_usage, D3DFMT_X8R8G8B8, (D3DPOOL)flags.t_pool, &texture, NULL); + } + + void update_filter() { + if(!device) return; + if(lost && !recover()) return; + + switch(settings.filter) { default: + case Video::FilterPoint: flags.filter = D3DTEXF_POINT; break; + case Video::FilterLinear: flags.filter = D3DTEXF_LINEAR; break; + } + + device->SetSamplerState(0, D3DSAMP_MINFILTER, flags.filter); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, flags.filter); + } + + // Vertex format: + // + // 0----------1 + // | /| + // | / | + // | / | + // | / | + // | / | + // 2----------3 + // + // (x,y) screen coords, in pixels + // (u,v) texture coords, betweeen 0.0 (top, left) to 1.0 (bottom, right) + void set_vertex( + uint32_t px, uint32_t py, uint32_t pw, uint32_t ph, + uint32_t tw, uint32_t th, + uint32_t x, uint32_t y, uint32_t w, uint32_t h + ) { + d3dvertex vertex[4]; + vertex[0].x = vertex[2].x = (double)(x - 0.5); + vertex[1].x = vertex[3].x = (double)(x + w - 0.5); + vertex[0].y = vertex[1].y = (double)(y - 0.5); + vertex[2].y = vertex[3].y = (double)(y + h - 0.5); + + //Z-buffer and RHW are unused for 2D blit, set to normal values + vertex[0].z = vertex[1].z = vertex[2].z = vertex[3].z = 0.0; + vertex[0].rhw = vertex[1].rhw = vertex[2].rhw = vertex[3].rhw = 1.0; + + double rw = (double)w / (double)pw * (double)tw; + double rh = (double)h / (double)ph * (double)th; + vertex[0].u = vertex[2].u = (double)(px ) / rw; + vertex[1].u = vertex[3].u = (double)(px + w) / rw; + vertex[0].v = vertex[1].v = (double)(py ) / rh; + vertex[2].v = vertex[3].v = (double)(py + h) / rh; + + vertex_buffer->Lock(0, sizeof(d3dvertex) * 4, (void**)&vertex_ptr, 0); + memcpy(vertex_ptr, vertex, sizeof(d3dvertex) * 4); + vertex_buffer->Unlock(); + + device->SetStreamSource(0, vertex_buffer, 0, sizeof(d3dvertex)); + } + + void clear() { + if(lost && !recover()) return; + + texture->GetLevelDesc(0, &d3dsd); + texture->GetSurfaceLevel(0, &surface); + + if(surface) { + device->ColorFill(surface, 0, D3DCOLOR_XRGB(0x00, 0x00, 0x00)); + surface->Release(); + } + + //clear primary display and all backbuffers + for(unsigned i = 0; i < 3; i++) { + device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00, 0x00, 0x00), 1.0f, 0); + device->Present(0, 0, 0, 0); + } + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + if(lost && !recover()) return false; + + if(width != settings.width || height != settings.height) { + resize(settings.width = width, settings.height = height); + } + + texture->GetLevelDesc(0, &d3dsd); + texture->GetSurfaceLevel(0, &surface); + + surface->LockRect(&d3dlr, 0, flags.lock); + pitch = d3dlr.Pitch; + return data = (uint32_t*)d3dlr.pBits; + } + + void unlock() { + surface->UnlockRect(); + surface->Release(); + } + + void refresh() { + if(lost && !recover()) return; + + RECT rd, rs; //dest, source rectangles + GetClientRect(settings.handle, &rd); + SetRect(&rs, 0, 0, settings.width, settings.height); + + //if output size changed, driver must be re-initialized. + //failure to do so causes scaling issues on some video drivers. + if(state.width != rd.right || state.height != rd.bottom) { + init(); + set_shader(shader_source_markup); + return; + } + + if(caps.shader && effect) { + device->BeginScene(); + set_vertex(0, 0, settings.width, settings.height, iwidth, iheight, 0, 0, rd.right, rd.bottom); + + D3DXVECTOR4 rubyTextureSize; + rubyTextureSize.x = iwidth; + rubyTextureSize.y = iheight; + rubyTextureSize.z = 1.0 / iheight; + rubyTextureSize.w = 1.0 / iwidth; + effect->SetVector("rubyTextureSize", &rubyTextureSize); + + D3DXVECTOR4 rubyInputSize; + rubyInputSize.x = settings.width; + rubyInputSize.y = settings.height; + rubyInputSize.z = 1.0 / settings.height; + rubyInputSize.w = 1.0 / settings.width; + effect->SetVector("rubyInputSize", &rubyInputSize); + + D3DXVECTOR4 rubyOutputSize; + rubyOutputSize.x = rd.right; + rubyOutputSize.y = rd.bottom; + rubyOutputSize.z = 1.0 / rd.bottom; + rubyOutputSize.w = 1.0 / rd.right; + effect->SetVector("rubyOutputSize", &rubyOutputSize); + + UINT passes; + effect->Begin(&passes, 0); + effect->SetTexture("rubyTexture", texture); + device->SetTexture(0, texture); + for(unsigned pass = 0; pass < passes; pass++) { + effect->BeginPass(pass); + device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + effect->EndPass(); + } + effect->End(); + device->EndScene(); + } else { + device->BeginScene(); + set_vertex(0, 0, settings.width, settings.height, iwidth, iheight, 0, 0, rd.right, rd.bottom); + device->SetTexture(0, texture); + device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + device->EndScene(); + } + + if(settings.synchronize) { + while(true) { + D3DRASTER_STATUS status; + device->GetRasterStatus(0, &status); + if(status.InVBlank == true) break; + } + } + + if(device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) lost = true; + } + + void set_shader(const char *source) { + if(!caps.shader) return; + + if(effect) { + effect->Release(); + effect = NULL; + } + + if(!source || !*source) { + shader_source_markup = ""; + return; + } + shader_source_markup = source; + + BML::Document document(shader_source_markup); + bool is_hlsl = document["shader"]["language"].value == "HLSL"; + string shader_source = document["shader"].value; + if(shader_source == "") return; + + HMODULE d3dx; + for(unsigned i = 0; i < 256; i++) { + char t[256]; + sprintf(t, "d3dx9_%u.dll", i); + d3dx = LoadLibraryW(utf16_t(t)); + if(d3dx) break; + } + if(!d3dx) d3dx = LoadLibraryW(L"d3dx9.dll"); + if(!d3dx) return; + + EffectProc effectProc = (EffectProc)GetProcAddress(d3dx, "D3DXCreateEffect"); + TextureProc textureProc = (TextureProc)GetProcAddress(d3dx, "D3DXCreateTextureFromFileA"); + + LPD3DXBUFFER pBufferErrors = NULL; + effectProc(device, shader_source, lstrlenA(shader_source), NULL, NULL, 0, NULL, &effect, &pBufferErrors); + + D3DXHANDLE hTech; + effect->FindNextValidTechnique(NULL, &hTech); + effect->SetTechnique(hTech); + } + + bool init() { + term(); + + RECT rd; + GetClientRect(settings.handle, &rd); + state.width = rd.right; + state.height = rd.bottom; + + lpd3d = Direct3DCreate9(D3D_SDK_VERSION); + if(!lpd3d) return false; + + memset(&presentation, 0, sizeof(presentation)); + presentation.Flags = D3DPRESENTFLAG_VIDEO; + presentation.SwapEffect = D3DSWAPEFFECT_FLIP; + presentation.hDeviceWindow = settings.handle; + presentation.BackBufferCount = 1; + presentation.MultiSampleType = D3DMULTISAMPLE_NONE; + presentation.MultiSampleQuality = 0; + presentation.EnableAutoDepthStencil = false; + presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + presentation.Windowed = true; + presentation.BackBufferFormat = D3DFMT_UNKNOWN; + presentation.BackBufferWidth = 0; + presentation.BackBufferHeight = 0; + + if(lpd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.handle, + D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) { + return false; + } + + device->GetDeviceCaps(&d3dcaps); + + caps.dynamic = bool(d3dcaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES); + caps.shader = d3dcaps.PixelShaderVersion > D3DPS_VERSION(1, 4); + + if(caps.dynamic == true) { + flags.t_usage = D3DUSAGE_DYNAMIC; + flags.v_usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC; + flags.t_pool = D3DPOOL_DEFAULT; + flags.v_pool = D3DPOOL_DEFAULT; + flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD; + } else { + flags.t_usage = 0; + flags.v_usage = D3DUSAGE_WRITEONLY; + flags.t_pool = D3DPOOL_MANAGED; + flags.v_pool = D3DPOOL_MANAGED; + flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD; + } + + lost = false; + recover(); + return true; + } + + void release_resources() { + if(effect) { effect->Release(); effect = 0; } + if(vertex_buffer) { vertex_buffer->Release(); vertex_buffer = 0; } + if(surface) { surface->Release(); surface = 0; } + if(texture) { texture->Release(); texture = 0; } + } + + void term() { + release_resources(); + if(device) { device->Release(); device = 0; } + if(lpd3d) { lpd3d->Release(); lpd3d = 0; } + } + + pVideoD3D() { + effect = 0; + vertex_buffer = 0; + surface = 0; + texture = 0; + device = 0; + lpd3d = 0; + lost = true; + + settings.handle = 0; + settings.synchronize = false; + settings.filter = Video::FilterLinear; + } +}; + +DeclareVideo(D3D) + +}; + +#undef D3DVERTEX diff --git a/ruby/video/directdraw.cpp b/ruby/video/directdraw.cpp new file mode 100755 index 00000000..5a77ec44 --- /dev/null +++ b/ruby/video/directdraw.cpp @@ -0,0 +1,186 @@ +#include + +namespace ruby { + +class pVideoDD { +public: + LPDIRECTDRAW lpdd; + LPDIRECTDRAW7 lpdd7; + LPDIRECTDRAWSURFACE7 screen, raster; + LPDIRECTDRAWCLIPPER clipper; + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + unsigned iwidth, iheight; + + struct { + HWND handle; + bool synchronize; + + unsigned width; + unsigned height; + } settings; + + bool cap(const string& name) { + if(name == Video::Handle) return true; + if(name == Video::Synchronize) return true; + return false; + } + + any get(const string& name) { + if(name == Video::Handle) return (uintptr_t)settings.handle; + if(name == Video::Synchronize) return settings.synchronize; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Handle) { + settings.handle = (HWND)any_cast(value); + return true; + } + + if(name == Video::Synchronize) { + settings.synchronize = any_cast(value); + return true; + } + + return false; + } + + void resize(unsigned width, unsigned height) { + if(iwidth >= width && iheight >= height) return; + + iwidth = max(width, iwidth); + iheight = max(height, iheight); + + if(raster) raster->Release(); + + screen->GetSurfaceDesc(&ddsd); + int depth = ddsd.ddpfPixelFormat.dwRGBBitCount; + if(depth == 32) goto try_native_surface; + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; //DDSCAPS_SYSTEMMEMORY + ddsd.dwWidth = iwidth; + ddsd.dwHeight = iheight; + + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + ddsd.ddpfPixelFormat.dwRGBBitCount = 32; + ddsd.ddpfPixelFormat.dwRBitMask = 0xff0000; + ddsd.ddpfPixelFormat.dwGBitMask = 0x00ff00; + ddsd.ddpfPixelFormat.dwBBitMask = 0x0000ff; + + if(lpdd7->CreateSurface(&ddsd, &raster, 0) == DD_OK) return clear(); + + try_native_surface: + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; //DDSCAPS_SYSTEMMEMORY + ddsd.dwWidth = iwidth; + ddsd.dwHeight = iheight; + + if(lpdd7->CreateSurface(&ddsd, &raster, 0) == DD_OK) return clear(); + } + + void clear() { + DDBLTFX fx; + fx.dwSize = sizeof(DDBLTFX); + fx.dwFillColor = 0x00000000; + screen->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); + raster->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + if(width != settings.width || height != settings.height) { + resize(settings.width = width, settings.height = height); + } + + if(raster->Lock(0, &ddsd, DDLOCK_WAIT, 0) != DD_OK) { + raster->Restore(); + if(raster->Lock(0, &ddsd, DDLOCK_WAIT, 0) != DD_OK) return false; + } + pitch = ddsd.lPitch; + return data = (uint32_t*)ddsd.lpSurface; + } + + void unlock() { + raster->Unlock(0); + } + + void refresh() { + if(settings.synchronize) { + while(true) { + BOOL in_vblank; + lpdd7->GetVerticalBlankStatus(&in_vblank); + if(in_vblank == true) break; + } + } + + HRESULT hr; + RECT rd, rs; + SetRect(&rs, 0, 0, settings.width, settings.height); + + POINT p = { 0, 0 }; + ClientToScreen(settings.handle, &p); + GetClientRect(settings.handle, &rd); + OffsetRect(&rd, p.x, p.y); + + if(screen->Blt(&rd, raster, &rs, DDBLT_WAIT, 0) == DDERR_SURFACELOST) { + screen->Restore(); + raster->Restore(); + } + } + + bool init() { + term(); + + DirectDrawCreate(0, &lpdd, 0); + lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7); + if(lpdd) { lpdd->Release(); lpdd = 0; } + + lpdd7->SetCooperativeLevel(settings.handle, DDSCL_NORMAL); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + lpdd7->CreateSurface(&ddsd, &screen, 0); + + lpdd7->CreateClipper(0, &clipper, 0); + clipper->SetHWnd(0, settings.handle); + screen->SetClipper(clipper); + + raster = 0; + iwidth = 0; + iheight = 0; + resize(settings.width = 256, settings.height = 256); + + return true; + } + + void term() { + if(clipper) { clipper->Release(); clipper = 0; } + if(raster) { raster->Release(); raster = 0; } + if(screen) { screen->Release(); screen = 0; } + if(lpdd7) { lpdd7->Release(); lpdd7 = 0; } + if(lpdd) { lpdd->Release(); lpdd = 0; } + } + + pVideoDD() { + lpdd = 0; + lpdd7 = 0; + screen = 0; + raster = 0; + clipper = 0; + + settings.handle = 0; + } +}; + +DeclareVideo(DD) + +}; diff --git a/ruby/video/gdi.cpp b/ruby/video/gdi.cpp new file mode 100755 index 00000000..c79f6d65 --- /dev/null +++ b/ruby/video/gdi.cpp @@ -0,0 +1,100 @@ +#include + +namespace ruby { + +class pVideoGDI { +public: + uint32_t *buffer; + HBITMAP bitmap; + HDC bitmapdc; + BITMAPINFO bmi; + + struct { + HWND handle; + + unsigned width; + unsigned height; + } settings; + + bool cap(const string& name) { + if(name == Video::Handle) return true; + return false; + } + + any get(const string& name) { + if(name == Video::Handle) return (uintptr_t)settings.handle; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Handle) { + settings.handle = (HWND)any_cast(value); + return true; + } + + return false; + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + settings.width = width; + settings.height = height; + + pitch = 1024 * 4; + return data = buffer; + } + + void unlock() {} + + void clear() {} + + void refresh() { + RECT rc; + GetClientRect(settings.handle, &rc); + + SetDIBits(bitmapdc, bitmap, 0, settings.height, (void*)buffer, &bmi, DIB_RGB_COLORS); + HDC hdc = GetDC(settings.handle); + StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, bitmapdc, 0, 1024 - settings.height, settings.width, settings.height, SRCCOPY); + ReleaseDC(settings.handle, hdc); + } + + bool init() { + HDC hdc = GetDC(settings.handle); + bitmapdc = CreateCompatibleDC(hdc); + assert(bitmapdc); + bitmap = CreateCompatibleBitmap(hdc, 1024, 1024); + assert(bitmap); + SelectObject(bitmapdc, bitmap); + ReleaseDC(settings.handle, hdc); + + memset(&bmi, 0, sizeof(BITMAPINFO)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = 1024; + bmi.bmiHeader.biHeight = -1024; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; //biBitCount of 15 is invalid, biBitCount of 16 is really RGB555 + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 1024 * 1024 * sizeof(uint32_t); + + settings.width = 256; + settings.height = 256; + return true; + } + + void term() { + DeleteObject(bitmap); + DeleteDC(bitmapdc); + } + + pVideoGDI() { + buffer = (uint32_t*)malloc(1024 * 1024 * sizeof(uint32_t)); + settings.handle = 0; + } + + ~pVideoGDI() { + if(buffer) free(buffer); + } +}; + +DeclareVideo(GDI) + +}; diff --git a/ruby/video/glx.cpp b/ruby/video/glx.cpp new file mode 100755 index 00000000..661703f0 --- /dev/null +++ b/ruby/video/glx.cpp @@ -0,0 +1,238 @@ +/* + video.glx + author: byuu + license: public domain + last updated: 2010-09-28 + + Design notes: + SGI's GLX is the X11/Xlib interface to OpenGL. + At the time of this writing, there are three relevant versions of the API: versions 1.2, 1.3 and 1.4. + + Version 1.2 was released on March 4th, 1997. + Version 1.3 was released on October 19th, 1998. + Version 1.4 was released on December 16th, 2005. + + Despite version 1.3 being roughly ten years old at this time, there are still many modern X11 GLX drivers + that lack full support for the specification. Most notable would be the official video drivers from ATI. + Given this, 1.4 support is pretty much hopeless to target. + + Luckily, each version has been designed to be backwards compatible with the previous version. As well, + version 1.2 is wholly sufficient, albeit less convenient, to implement this video module. + + Therefore, for the purpose of compatibility, this driver only uses GLX 1.2 or earlier API commands. + As well, it only uses raw Xlib API commands, so that it is compatible with any toolkit. +*/ + +#include "opengl.hpp" + +namespace ruby { + +//returns true once window is mapped (created and displayed onscreen) +static Bool glx_wait_for_map_notify(Display *d, XEvent *e, char *arg) { + return (e->type == MapNotify) && (e->xmap.window == (Window)arg); +} + +class pVideoGLX : public OpenGL { +public: + int (*glSwapInterval)(int); + + Display *display; + int screen; + Window xwindow; + Colormap colormap; + GLXContext glxcontext; + GLXWindow glxwindow; + + struct { + int version_major, version_minor; + bool double_buffer; + bool is_direct; + } glx; + + struct { + Window handle; + bool synchronize; + unsigned filter; + + unsigned width; + unsigned height; + } settings; + + bool cap(const string& name) { + if(name == Video::Handle) return true; + if(name == Video::Synchronize) return true; + if(name == Video::Filter) return true; + if(name == Video::Shader) return true; + if(name == Video::FragmentShader) return true; + if(name == Video::VertexShader) return true; + return false; + } + + any get(const string& name) { + if(name == Video::Handle) return (uintptr_t)settings.handle; + if(name == Video::Synchronize) return settings.synchronize; + if(name == Video::Filter) return settings.filter; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Handle) { + settings.handle = any_cast(value); + return true; + } + + if(name == Video::Synchronize) { + if(settings.synchronize != any_cast(value)) { + settings.synchronize = any_cast(value); + if(glSwapInterval) glSwapInterval(settings.synchronize); + return true; + } + } + + if(name == Video::Filter) { + settings.filter = any_cast(value); + return true; + } + + if(name == Video::Shader) { + OpenGL::set_shader(any_cast(value)); + settings.filter = OpenGL::fragmentfilter; + return true; + } + + if(name == Video::FragmentShader) { + OpenGL::set_fragment_shader(any_cast(value)); + return true; + } + + if(name == Video::VertexShader) { + OpenGL::set_vertex_shader(any_cast(value)); + return true; + } + + return false; + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + resize(width, height); + settings.width = width; + settings.height = height; + return OpenGL::lock(data, pitch); + } + + void unlock() { + } + + void clear() { + OpenGL::clear(); + if(glx.double_buffer) glXSwapBuffers(display, glxwindow); + } + + void refresh() { + //we must ensure that the child window is the same size as the parent window. + //unfortunately, we cannot hook the parent window resize event notification, + //as we did not create the parent window, nor have any knowledge of the toolkit used. + //therefore, inelegant as it may be, we query each window size and resize as needed. + XWindowAttributes parent, child; + XGetWindowAttributes(display, settings.handle, &parent); + XGetWindowAttributes(display, xwindow, &child); + if(child.width != parent.width || child.height != parent.height) { + XResizeWindow(display, xwindow, parent.width, parent.height); + } + + OpenGL::refresh(settings.filter == Video::FilterLinear, + settings.width, settings.height, parent.width, parent.height); + if(glx.double_buffer) glXSwapBuffers(display, glxwindow); + } + + bool init() { + term(); + + display = XOpenDisplay(0); + screen = DefaultScreen(display); + glXQueryVersion(display, &glx.version_major, &glx.version_minor); + //require GLX 1.2+ API + if(glx.version_major < 1 || (glx.version_major == 1 && glx.version_minor < 2)) return false; + + XWindowAttributes window_attributes; + XGetWindowAttributes(display, settings.handle, &window_attributes); + + //let GLX determine the best Visual to use for GL output; provide a few hints + //note: some video drivers will override double buffering attribute + int attributelist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None }; + XVisualInfo *vi = glXChooseVisual(display, screen, attributelist); + + //Window settings.handle has already been realized, most likely with DefaultVisual. + //GLX requires that the GL output window has the same Visual as the GLX context. + //it is not possible to change the Visual of an already realized (created) window. + //therefore a new child window, using the same GLX Visual, must be created and binded to settings.handle. + colormap = XCreateColormap(display, RootWindow(display, vi->screen), vi->visual, AllocNone); + XSetWindowAttributes attributes; + attributes.colormap = colormap; + attributes.border_pixel = 0; + attributes.event_mask = StructureNotifyMask; + xwindow = XCreateWindow(display, /* parent = */ settings.handle, + /* x = */ 0, /* y = */ 0, window_attributes.width, window_attributes.height, + /* border_width = */ 0, vi->depth, InputOutput, vi->visual, + CWColormap | CWBorderPixel | CWEventMask, &attributes); + XSetWindowBackground(display, xwindow, /* color = */ 0); + XMapWindow(display, xwindow); + XEvent event; + //window must be realized (appear onscreen) before we make the context current + XIfEvent(display, &event, glx_wait_for_map_notify, (char*)xwindow); + + glxcontext = glXCreateContext(display, vi, /* sharelist = */ 0, /* direct = */ GL_TRUE); + glXMakeCurrent(display, glxwindow = xwindow, glxcontext); + + //read attributes of frame buffer for later use, as requested attributes from above are not always granted + int value = 0; + glXGetConfig(display, vi, GLX_DOUBLEBUFFER, &value); + glx.double_buffer = value; + glx.is_direct = glXIsDirect(display, glxcontext); + + OpenGL::init(); + settings.width = 256; + settings.height = 256; + + //vertical synchronization + if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI"); + if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA"); + if( glSwapInterval) glSwapInterval(settings.synchronize); + + return true; + } + + void term() { + OpenGL::term(); + + if(glxcontext) { + glXDestroyContext(display, glxcontext); + glxcontext = 0; + } + + if(xwindow) { + XUnmapWindow(display, xwindow); + xwindow = 0; + } + + if(colormap) { + XFreeColormap(display, colormap); + colormap = 0; + } + } + + pVideoGLX() : glSwapInterval(0) { + settings.handle = 0; + settings.synchronize = false; + xwindow = 0; + colormap = 0; + glxcontext = 0; + glxwindow = 0; + } + + ~pVideoGLX() { term(); } +}; + +DeclareVideo(GLX) + +}; diff --git a/ruby/video/opengl.hpp b/ruby/video/opengl.hpp new file mode 100755 index 00000000..a606c752 --- /dev/null +++ b/ruby/video/opengl.hpp @@ -0,0 +1,231 @@ +#include + +#if defined(PLATFORM_X) + #include + #define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name)) +#elif defined(PLATFORM_WIN) + #include + #define glGetProcAddress(name) wglGetProcAddress(name) +#else + #error "ruby::OpenGL: unsupported platform" +#endif + +PFNGLCREATEPROGRAMPROC glCreateProgram = 0; +PFNGLUSEPROGRAMPROC glUseProgram = 0; +PFNGLCREATESHADERPROC glCreateShader = 0; +PFNGLDELETESHADERPROC glDeleteShader = 0; +PFNGLSHADERSOURCEPROC glShaderSource = 0; +PFNGLCOMPILESHADERPROC glCompileShader = 0; +PFNGLATTACHSHADERPROC glAttachShader = 0; +PFNGLDETACHSHADERPROC glDetachShader = 0; +PFNGLLINKPROGRAMPROC glLinkProgram = 0; +PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = 0; +PFNGLUNIFORM1IPROC glUniform1i = 0; +PFNGLUNIFORM2FVPROC glUniform2fv = 0; +PFNGLUNIFORM4FVPROC glUniform4fv = 0; + +class OpenGL { +public: + GLuint gltexture; + GLuint glprogram; + GLuint fragmentshader; + unsigned fragmentfilter; + GLuint vertexshader; + bool shader_support; + + uint32_t *buffer; + unsigned iwidth, iheight; + + void resize(unsigned width, unsigned height) { + if(gltexture == 0) glGenTextures(1, &gltexture); + iwidth = max(width, iwidth ); + iheight = max(height, iheight); + if(buffer) delete[] buffer; + buffer = new uint32_t[iwidth * iheight](); + + glBindTexture(GL_TEXTURE_2D, gltexture); + glPixelStorei(GL_UNPACK_ROW_LENGTH, iwidth); + glTexImage2D(GL_TEXTURE_2D, + /* mip-map level = */ 0, /* internal format = */ GL_RGBA, + iwidth, iheight, /* border = */ 0, /* format = */ GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + } + + bool lock(uint32_t *&data, unsigned &pitch) { + pitch = iwidth * sizeof(uint32_t); + return data = buffer; + } + + void clear() { + memset(buffer, 0, iwidth * iheight * sizeof(uint32_t)); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glFlush(); + } + + void refresh(bool smooth, unsigned inwidth, unsigned inheight, unsigned outwidth, unsigned outheight) { + if(shader_support) { + glUseProgram(glprogram); + GLint location; + + float inputSize[2] = { (float)inwidth, (float)inheight }; + location = glGetUniformLocation(glprogram, "rubyInputSize"); + glUniform2fv(location, 1, inputSize); + + float outputSize[2] = { (float)outwidth, (float)outheight }; + location = glGetUniformLocation(glprogram, "rubyOutputSize"); + glUniform2fv(location, 1, outputSize); + + float textureSize[2] = { (float)iwidth, (float)iheight }; + location = glGetUniformLocation(glprogram, "rubyTextureSize"); + glUniform2fv(location, 1, textureSize); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? GL_LINEAR : GL_NEAREST); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, outwidth, 0, outheight, -1.0, 1.0); + glViewport(0, 0, outwidth, outheight); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glPixelStorei(GL_UNPACK_ROW_LENGTH, iwidth); + glTexSubImage2D(GL_TEXTURE_2D, + /* mip-map level = */ 0, /* x = */ 0, /* y = */ 0, + inwidth, inheight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + + //OpenGL projection sets 0,0 as *bottom-left* of screen. + //therefore, below vertices flip image to support top-left source. + //texture range = x1:0.0, y1:0.0, x2:1.0, y2:1.0 + //vertex range = x1:0, y1:0, x2:width, y2:height + double w = double(inwidth) / double(iwidth); + double h = double(inheight) / double(iheight); + int u = outwidth; + int v = outheight; + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(0, 0); glVertex3i(0, v, 0); + glTexCoord2f(w, 0); glVertex3i(u, v, 0); + glTexCoord2f(0, h); glVertex3i(0, 0, 0); + glTexCoord2f(w, h); glVertex3i(u, 0, 0); + glEnd(); + + glFlush(); + + if(shader_support) { + glUseProgram(0); + } + } + + void set_shader(const char *source) { + if(!shader_support) return; + + if(fragmentshader) { + glDetachShader(glprogram, fragmentshader); + glDeleteShader(fragmentshader); + fragmentshader = 0; + } + + if(vertexshader) { + glDetachShader(glprogram, vertexshader); + glDeleteShader(vertexshader); + vertexshader = 0; + } + + if(source) { + BML::Document document(source); + bool is_glsl = document["shader"]["language"].value == "GLSL"; + fragmentfilter = document["shader"]["fragment"]["filter"].value == "linear" ? 1 : 0; + string fragment_source = document["shader"]["fragment"].value; + string vertex_source = document["shader"]["vertex"].value; + + if(is_glsl) { + if(fragment_source != "") set_fragment_shader(fragment_source); + if(vertex_source != "") set_vertex_shader(vertex_source); + } + } + + glLinkProgram(glprogram); + } + + void set_fragment_shader(const char *source) { + fragmentshader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentshader, 1, &source, 0); + glCompileShader(fragmentshader); + glAttachShader(glprogram, fragmentshader); + } + + void set_vertex_shader(const char *source) { + vertexshader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexshader, 1, &source, 0); + glCompileShader(vertexshader); + glAttachShader(glprogram, vertexshader); + } + + void init() { + //disable unused features + glDisable(GL_ALPHA_TEST); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDisable(GL_POLYGON_SMOOTH); + glDisable(GL_STENCIL_TEST); + + //enable useful and required features + glEnable(GL_DITHER); + glEnable(GL_TEXTURE_2D); + + //bind shader functions + glCreateProgram = (PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgram"); + glUseProgram = (PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgram"); + glCreateShader = (PFNGLCREATESHADERPROC)glGetProcAddress("glCreateShader"); + glDeleteShader = (PFNGLDELETESHADERPROC)glGetProcAddress("glDeleteShader"); + glShaderSource = (PFNGLSHADERSOURCEPROC)glGetProcAddress("glShaderSource"); + glCompileShader = (PFNGLCOMPILESHADERPROC)glGetProcAddress("glCompileShader"); + glAttachShader = (PFNGLATTACHSHADERPROC)glGetProcAddress("glAttachShader"); + glDetachShader = (PFNGLDETACHSHADERPROC)glGetProcAddress("glDetachShader"); + glLinkProgram = (PFNGLLINKPROGRAMPROC)glGetProcAddress("glLinkProgram"); + glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)glGetProcAddress("glGetUniformLocation"); + glUniform1i = (PFNGLUNIFORM1IPROC)glGetProcAddress("glUniform1i"); + glUniform2fv = (PFNGLUNIFORM2FVPROC)glGetProcAddress("glUniform2fv"); + glUniform4fv = (PFNGLUNIFORM4FVPROC)glGetProcAddress("glUniform4fv"); + + shader_support = glCreateProgram && glUseProgram && glCreateShader + && glDeleteShader && glShaderSource && glCompileShader && glAttachShader + && glDetachShader && glLinkProgram && glGetUniformLocation + && glUniform1i && glUniform2fv && glUniform4fv; + + if(shader_support) glprogram = glCreateProgram(); + + //create surface texture + resize(256, 256); + } + + void term() { + if(gltexture) { + glDeleteTextures(1, &gltexture); + gltexture = 0; + } + + if(buffer) { + delete[] buffer; + buffer = 0; + iwidth = 0; + iheight = 0; + } + } + + OpenGL() { + gltexture = 0; + glprogram = 0; + fragmentshader = 0; + fragmentfilter = 0; + vertexshader = 0; + + buffer = 0; + iwidth = 0; + iheight = 0; + } +}; diff --git a/ruby/video/qtopengl.cpp b/ruby/video/qtopengl.cpp new file mode 100755 index 00000000..c357c403 --- /dev/null +++ b/ruby/video/qtopengl.cpp @@ -0,0 +1,174 @@ +#ifdef __APPLE__ + #include +#endif + +namespace ruby { + +class pVideoQtOpenGL { +public: + QWidget *parent; + QVBoxLayout *layout; + + class RubyGLWidget : public QGLWidget { + public: + GLuint texture; + unsigned textureWidth, textureHeight; + + uint32_t *buffer; + unsigned rasterWidth, rasterHeight; + + bool synchronize; + unsigned filter; + + void resize(unsigned width, unsigned height) { + if(width > textureWidth || height > textureHeight) { + textureWidth = max(width, textureWidth); + textureHeight = max(height, textureHeight); + + if(buffer) { + delete[] buffer; + glDeleteTextures(1, &texture); + } + + buffer = new uint32_t[textureWidth * textureHeight]; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glPixelStorei(GL_UNPACK_ROW_LENGTH, textureWidth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureWidth, textureHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + } + } + + void updateSynchronization() { + #ifdef __APPLE__ + makeCurrent(); + CGLContextObj context = CGLGetCurrentContext(); + GLint value = synchronize; //0 = draw immediately (no vsync), 1 = draw once per frame (vsync) + CGLSetParameter(context, kCGLCPSwapInterval, &value); + #endif + } + + void paintGL() { + unsigned outputWidth = width(); + unsigned outputHeight = height(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, outputWidth, 0, outputHeight, -1.0, 1.0); + glViewport(0, 0, outputWidth, outputHeight); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter == Video::FilterPoint) ? GL_NEAREST : GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter == Video::FilterPoint) ? GL_NEAREST : GL_LINEAR); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rasterWidth, rasterHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + + double w = (double)rasterWidth / (double)textureWidth; + double h = (double)rasterHeight / (double)textureHeight; + unsigned u = outputWidth; + unsigned v = outputHeight; + + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(0, 0); glVertex3i(0, v, 0); + glTexCoord2f(w, 0); glVertex3i(u, v, 0); + glTexCoord2f(0, h); glVertex3i(0, 0, 0); + glTexCoord2f(w, h); glVertex3i(u, 0, 0); + glEnd(); + } + + void initializeGL() { + format().setDoubleBuffer(true); + + texture = 0; + textureWidth = 0; + textureHeight = 0; + buffer = 0; + resize(rasterWidth = 256, rasterHeight = 256); + + glDisable(GL_ALPHA_TEST); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDisable(GL_POLYGON_SMOOTH); + glDisable(GL_STENCIL_TEST); + glEnable(GL_DITHER); + glEnable(GL_TEXTURE_2D); + glClearColor(0.0, 0.0, 0.0, 0.0); + } + } *widget; + + bool cap(const string& name) { + if(name == Video::Synchronize) return true; + if(name == Video::Filter) return true; + if(name == "QWidget") return true; + return false; + } + + any get(const string& name) { + if(name == Video::Synchronize) return widget->synchronize; + if(name == Video::Filter) return widget->filter; + if(name == "QWidget") return parent; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Synchronize) { + widget->synchronize = any_cast(value); + widget->updateSynchronization(); + return true; + } + + if(name == Video::Filter) { + widget->filter = any_cast(value); + return true; + } + + if(name == "QWidget") { + parent = any_cast(value); + return true; + } + + return false; + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + widget->resize(width, height); + widget->rasterWidth = width; + widget->rasterHeight = height; + + pitch = widget->textureWidth * sizeof(uint32_t); + return data = widget->buffer; + } + + void unlock() { + } + + void clear() { + memset(widget->buffer, 0, widget->textureWidth * widget->textureHeight * sizeof(uint32_t)); + widget->updateGL(); + } + + void refresh() { + widget->updateGL(); + } + + bool init() { + layout = new QVBoxLayout; + layout->setMargin(0); + + widget = new RubyGLWidget; + widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + layout->addWidget(widget); + parent->setLayout(layout); + + return true; + } + + void term() { + } +}; + +DeclareVideo(QtOpenGL) + +}; diff --git a/ruby/video/qtraster.cpp b/ruby/video/qtraster.cpp new file mode 100755 index 00000000..414689b9 --- /dev/null +++ b/ruby/video/qtraster.cpp @@ -0,0 +1,126 @@ +namespace ruby { + +struct VideoQtRasterContext { + QImage *image; + unsigned width, height; + unsigned filter; +} context; + +class pVideoQtRaster { +public: + QWidget *parent; + QVBoxLayout *layout; + + struct QtImage : public QWidget { + VideoQtRasterContext &context; + + void paintEvent(QPaintEvent*) { + if(context.image == 0) return; + QPainter painter(this); + + if(size().width() == context.width && size().height() == context.height) { + painter.drawImage(0, 0, *context.image); + } else { + Qt::TransformationMode mode = Qt::FastTransformation; + if(context.filter == Video::FilterLinear) mode = Qt::SmoothTransformation; + painter.drawImage(0, 0, context.image->scaled(size(), Qt::IgnoreAspectRatio, mode)); + } + } + + QtImage(QWidget *parent, VideoQtRasterContext &context_) : QWidget(parent), context(context_) {} + } *widget; + + bool cap(const string& name) { + if(name == Video::Filter) return true; + if(name == "QWidget") return true; + return false; + } + + any get(const string& name) { + if(name == Video::Filter) return context.filter; + if(name == "QWidget") return parent; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Filter) { + context.filter = any_cast(value); + return true; + } + + if(name == "QWidget") { + parent = any_cast(value); + return true; + } + + return false; + } + + void resize(unsigned width, unsigned height) { + if(context.width != width || context.height != height) { + if(context.image) delete context.image; + context.image = new QImage(context.width = width, context.height = height, QImage::Format_RGB32); + } + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + //if image size has changed since last lock(), re-allocate buffer to match new size + if(width != context.width || height != context.height) resize(width, height); + + pitch = width * sizeof(uint32_t); + return data = (uint32_t*)context.image->bits(); + } + + void unlock() { + } + + void clear() { + context.image->fill(0); + widget->update(); + } + + void refresh() { + widget->update(); + } + + bool init() { + term(); + + layout = new QVBoxLayout; + layout->setMargin(0); + + context.image = 0; + context.width = 0; + context.height = 0; + context.filter = Video::FilterPoint; + resize(256, 256); + + widget = new QtImage(parent, context); + widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + layout->addWidget(widget); + parent->setLayout(layout); + clear(); + + return true; + } + + void term() { + if(context.image) delete context.image; + if(widget) delete widget; + if(layout) delete layout; + + context.image = 0; + widget = 0; + layout = 0; + } + + pVideoQtRaster() { + context.image = 0; + widget = 0; + layout = 0; + } +}; + +DeclareVideo(QtRaster) + +}; diff --git a/ruby/video/sdl.cpp b/ruby/video/sdl.cpp new file mode 100755 index 00000000..8f70342e --- /dev/null +++ b/ruby/video/sdl.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include + +namespace ruby { + +class pVideoSDL { +public: + Display *display; + SDL_Surface *screen, *buffer; + unsigned iwidth, iheight; + + struct { + uintptr_t handle; + + unsigned width; + unsigned height; + } settings; + + bool cap(const string& name) { + if(name == Video::Handle) return true; + return false; + } + + any get(const string& name) { + if(name == Video::Handle) return settings.handle; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Handle) { + settings.handle = any_cast(value); + return true; + } + + return false; + } + + void resize(unsigned width, unsigned height) { + if(iwidth >= width && iheight >= height) return; + + iwidth = max(width, iwidth); + iheight = max(height, iheight); + + if(buffer) SDL_FreeSurface(buffer); + buffer = SDL_CreateRGBSurface( + SDL_SWSURFACE, iwidth, iheight, 32, + 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 + ); + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + if(width != settings.width || height != settings.height) { + resize(settings.width = width, settings.height = height); + } + + if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer); + pitch = buffer->pitch; + return data = (uint32_t*)buffer->pixels; + } + + void unlock() { + if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer); + } + + void clear() { + if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer); + for(unsigned y = 0; y < iheight; y++) { + uint32_t *data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2); + for(unsigned x = 0; x < iwidth; x++) *data++ = 0xff000000; + } + if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer); + refresh(); + } + + void refresh() { + //ruby input is X8R8G8B8, top 8-bits are ignored. + //as SDL forces us to use a 32-bit buffer, we must set alpha to 255 (full opacity) + //to prevent blending against the window beneath when X window visual is 32-bits. + if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer); + for(unsigned y = 0; y < settings.height; y++) { + uint32_t *data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2); + for(unsigned x = 0; x < settings.width; x++) *data++ |= 0xff000000; + } + if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer); + + XWindowAttributes attributes; + XGetWindowAttributes(display, settings.handle, &attributes); + + SDL_Rect src, dest; + + src.x = 0; + src.y = 0; + src.w = settings.width; + src.h = settings.height; + + dest.x = 0; + dest.y = 0; + dest.w = attributes.width; + dest.h = attributes.height; + + SDL_SoftStretch(buffer, &src, screen, &dest); + SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); + } + + bool init() { + display = XOpenDisplay(0); + + char env[512]; + sprintf(env, "SDL_WINDOWID=%ld", (long int)settings.handle); + putenv(env); + + SDL_InitSubSystem(SDL_INIT_VIDEO); + screen = SDL_SetVideoMode(2560, 1600, 32, SDL_HWSURFACE); + + buffer = 0; + iwidth = 0; + iheight = 0; + resize(settings.width = 256, settings.height = 256); + + return true; + } + + void term() { + XCloseDisplay(display); + SDL_FreeSurface(buffer); + SDL_QuitSubSystem(SDL_INIT_VIDEO); + } + + pVideoSDL() { + settings.handle = 0; + } +}; + +DeclareVideo(SDL) + +}; diff --git a/ruby/video/wgl.cpp b/ruby/video/wgl.cpp new file mode 100755 index 00000000..ce5d6be7 --- /dev/null +++ b/ruby/video/wgl.cpp @@ -0,0 +1,154 @@ +/* + video.wgl + authors: byuu, krom +*/ + +#include "opengl.hpp" + +namespace ruby { + +class pVideoWGL : public OpenGL { +public: + BOOL (APIENTRY *glSwapInterval)(int); + + HDC display; + HGLRC wglcontext; + HWND window; + HINSTANCE glwindow; + + struct { + HWND handle; + bool synchronize; + unsigned filter; + string shader; + + unsigned width; + unsigned height; + } settings; + + bool cap(const string& name) { + if(name == Video::Handle) return true; + if(name == Video::Synchronize) return true; + if(name == Video::Filter) return true; + if(name == Video::Shader) return true; + return false; + } + + any get(const string& name) { + if(name == Video::Handle) return (uintptr_t)settings.handle; + if(name == Video::Synchronize) return settings.synchronize; + if(name == Video::Filter) return settings.filter; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Handle) { + settings.handle = (HWND)any_cast(value); + return true; + } + + if(name == Video::Synchronize) { + if(settings.synchronize != any_cast(value)) { + settings.synchronize = any_cast(value); + if(wglcontext) { + init(); + OpenGL::set_shader(settings.shader); + } + } + } + + if(name == Video::Filter) { + settings.filter = any_cast(value); + return true; + } + + if(name == Video::Shader) { + settings.shader = any_cast(value); + OpenGL::set_shader(settings.shader); + settings.filter = OpenGL::fragmentfilter; + return true; + } + + return false; + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + resize(width, height); + settings.width = width; + settings.height = height; + return OpenGL::lock(data, pitch); + } + + void unlock() { + } + + void clear() { + OpenGL::clear(); + SwapBuffers(display); + } + + void refresh() { + RECT rc; + GetClientRect(settings.handle, &rc); + + OpenGL::refresh(settings.filter == Video::FilterLinear, + settings.width, settings.height, + rc.right - rc.left, rc.bottom - rc.top); + + SwapBuffers(display); + } + + bool init() { + term(); + + GLuint pixel_format; + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + + display = GetDC(settings.handle); + pixel_format = ChoosePixelFormat(display, &pfd); + SetPixelFormat(display, pixel_format, &pfd); + + wglcontext = wglCreateContext(display); + wglMakeCurrent(display, wglcontext); + + OpenGL::init(); + settings.width = 256; + settings.height = 256; + + //vertical synchronization + if(!glSwapInterval) glSwapInterval = (BOOL (APIENTRY*)(int))glGetProcAddress("wglSwapIntervalEXT"); + if( glSwapInterval) glSwapInterval(settings.synchronize); + + return true; + } + + void term() { + OpenGL::term(); + + if(wglcontext) { + wglDeleteContext(wglcontext); + wglcontext = 0; + } + } + + pVideoWGL() : glSwapInterval(0) { + settings.handle = 0; + settings.synchronize = false; + settings.filter = 0; + + window = 0; + wglcontext = 0; + glwindow = 0; + } + + ~pVideoWGL() { term(); } +}; + +DeclareVideo(WGL) + +}; diff --git a/ruby/video/xv.cpp b/ruby/video/xv.cpp new file mode 100755 index 00000000..10d51647 --- /dev/null +++ b/ruby/video/xv.cpp @@ -0,0 +1,498 @@ +#include +#include +#include +#include +#include + +extern "C" XvImage* XvShmCreateImage(Display*, XvPortID, int, char*, int, int, XShmSegmentInfo*); + +namespace ruby { + +class pVideoXv { +public: + uint32_t *buffer; + uint8_t *ytable, *utable, *vtable; + + enum XvFormat { + XvFormatRGB32, + XvFormatRGB24, + XvFormatRGB16, + XvFormatRGB15, + XvFormatYUY2, + XvFormatUYVY, + XvFormatUnknown + }; + + struct { + Display *display; + GC gc; + Window window; + Colormap colormap; + XShmSegmentInfo shminfo; + + int port; + int depth; + int visualid; + + XvImage *image; + XvFormat format; + uint32_t fourcc; + + unsigned width; + unsigned height; + } device; + + struct { + Window handle; + bool synchronize; + + unsigned width; + unsigned height; + } settings; + + bool cap(const string& name) { + if(name == Video::Handle) return true; + if(name == Video::Synchronize) { + return XInternAtom(XOpenDisplay(0), "XV_SYNC_TO_VBLANK", true) != None; + } + return false; + } + + any get(const string& name) { + if(name == Video::Handle) return settings.handle; + if(name == Video::Synchronize) return settings.synchronize; + return false; + } + + bool set(const string& name, const any& value) { + if(name == Video::Handle) { + settings.handle = any_cast(value); + return true; + } + + if(name == Video::Synchronize) { + Display *display = XOpenDisplay(0); + Atom atom = XInternAtom(display, "XV_SYNC_TO_VBLANK", true); + if(atom != None && device.port >= 0) { + settings.synchronize = any_cast(value); + XvSetPortAttribute(display, device.port, atom, settings.synchronize); + return true; + } + return false; + } + + return false; + } + + void resize(unsigned width, unsigned height) { + if(device.width >= width && device.height >= height) return; + device.width = max(width, device.width); + device.height = max(height, device.height); + + XShmDetach(device.display, &device.shminfo); + shmdt(device.shminfo.shmaddr); + shmctl(device.shminfo.shmid, IPC_RMID, NULL); + XFree(device.image); + delete[] buffer; + + device.image = XvShmCreateImage(device.display, device.port, device.fourcc, 0, device.width, device.height, &device.shminfo); + + device.shminfo.shmid = shmget(IPC_PRIVATE, device.image->data_size, IPC_CREAT | 0777); + device.shminfo.shmaddr = device.image->data = (char*)shmat(device.shminfo.shmid, 0, 0); + device.shminfo.readOnly = false; + XShmAttach(device.display, &device.shminfo); + + buffer = new uint32_t[device.width * device.height]; + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + if(width != settings.width || height != settings.height) { + resize(settings.width = width, settings.height = height); + } + + pitch = device.width * 4; + return data = buffer; + } + + void unlock() { + } + + void clear() { + memset(buffer, 0, device.width * device.height * sizeof(uint32_t)); + //clear twice in case video is double buffered ... + refresh(); + refresh(); + } + + void refresh() { + unsigned width = settings.width; + unsigned height = settings.height; + + XWindowAttributes target; + XGetWindowAttributes(device.display, device.window, &target); + + //we must ensure that the child window is the same size as the parent window. + //unfortunately, we cannot hook the parent window resize event notification, + //as we did not create the parent window, nor have any knowledge of the toolkit used. + //therefore, query each window size and resize as needed. + XWindowAttributes parent; + XGetWindowAttributes(device.display, settings.handle, &parent); + if(target.width != parent.width || target.height != parent.height) { + XResizeWindow(device.display, device.window, parent.width, parent.height); + } + + //update target width and height attributes + XGetWindowAttributes(device.display, device.window, &target); + + switch(device.format) { + case XvFormatRGB32: render_rgb32(width, height); break; + case XvFormatRGB24: render_rgb24(width, height); break; + case XvFormatRGB16: render_rgb16(width, height); break; + case XvFormatRGB15: render_rgb15(width, height); break; + case XvFormatYUY2: render_yuy2 (width, height); break; + case XvFormatUYVY: render_uyvy (width, height); break; + } + + XvShmPutImage(device.display, device.port, device.window, device.gc, device.image, + 0, 0, width, height, + 0, 0, target.width, target.height, + true); + } + + bool init() { + device.display = XOpenDisplay(0); + + if(!XShmQueryExtension(device.display)) { + fprintf(stderr, "VideoXv: XShm extension not found.\n"); + return false; + } + + //find an appropriate Xv port + device.port = -1; + XvAdaptorInfo *adaptor_info; + unsigned adaptor_count; + XvQueryAdaptors(device.display, DefaultRootWindow(device.display), &adaptor_count, &adaptor_info); + for(unsigned i = 0; i < adaptor_count; i++) { + //find adaptor that supports both input (memory->drawable) and image (drawable->screen) masks + if(adaptor_info[i].num_formats < 1) continue; + if(!(adaptor_info[i].type & XvInputMask)) continue; + if(!(adaptor_info[i].type & XvImageMask)) continue; + + device.port = adaptor_info[i].base_id; + device.depth = adaptor_info[i].formats->depth; + device.visualid = adaptor_info[i].formats->visual_id; + break; + } + XvFreeAdaptorInfo(adaptor_info); + if(device.port < 0) { + fprintf(stderr, "VideoXv: failed to find valid XvPort.\n"); + return false; + } + + //create child window to attach to parent window. + //this is so that even if parent window visual depth doesn't match Xv visual + //(common with composited windows), Xv can still render to child window. + XWindowAttributes window_attributes; + XGetWindowAttributes(device.display, settings.handle, &window_attributes); + + XVisualInfo visualtemplate; + visualtemplate.visualid = device.visualid; + visualtemplate.screen = DefaultScreen(device.display); + visualtemplate.depth = device.depth; + visualtemplate.visual = 0; + int visualmatches = 0; + XVisualInfo *visualinfo = XGetVisualInfo(device.display, VisualIDMask | VisualScreenMask | VisualDepthMask, &visualtemplate, &visualmatches); + if(visualmatches < 1 || !visualinfo->visual) { + if(visualinfo) XFree(visualinfo); + fprintf(stderr, "VideoXv: unable to find Xv-compatible visual.\n"); + return false; + } + + device.colormap = XCreateColormap(device.display, settings.handle, visualinfo->visual, AllocNone); + XSetWindowAttributes attributes; + attributes.colormap = device.colormap; + attributes.border_pixel = 0; + attributes.event_mask = StructureNotifyMask; + device.window = XCreateWindow(device.display, /* parent = */ settings.handle, + /* x = */ 0, /* y = */ 0, window_attributes.width, window_attributes.height, + /* border_width = */ 0, device.depth, InputOutput, visualinfo->visual, + CWColormap | CWBorderPixel | CWEventMask, &attributes); + XFree(visualinfo); + XSetWindowBackground(device.display, device.window, /* color = */ 0); + XMapWindow(device.display, device.window); + + device.gc = XCreateGC(device.display, device.window, 0, 0); + + //set colorkey to auto paint, so that Xv video output is always visible + Atom atom = XInternAtom(device.display, "XV_AUTOPAINT_COLORKEY", true); + if(atom != None) XvSetPortAttribute(device.display, device.port, atom, 1); + + //find optimal rendering format + device.format = XvFormatUnknown; + signed format_count; + XvImageFormatValues *format = XvListImageFormats(device.display, device.port, &format_count); + + if(device.format == XvFormatUnknown) for(signed i = 0; i < format_count; i++) { + if(format[i].type == XvRGB && format[i].bits_per_pixel == 32) { + device.format = XvFormatRGB32; + device.fourcc = format[i].id; + break; + } + } + + if(device.format == XvFormatUnknown) for(signed i = 0; i < format_count; i++) { + if(format[i].type == XvRGB && format[i].bits_per_pixel == 24) { + device.format = XvFormatRGB24; + device.fourcc = format[i].id; + break; + } + } + + if(device.format == XvFormatUnknown) for(signed i = 0; i < format_count; i++) { + if(format[i].type == XvRGB && format[i].bits_per_pixel <= 16 && format[i].red_mask == 0xf800) { + device.format = XvFormatRGB16; + device.fourcc = format[i].id; + break; + } + } + + if(device.format == XvFormatUnknown) for(signed i = 0; i < format_count; i++) { + if(format[i].type == XvRGB && format[i].bits_per_pixel <= 16 && format[i].red_mask == 0x7c00) { + device.format = XvFormatRGB15; + device.fourcc = format[i].id; + break; + } + } + + if(device.format == XvFormatUnknown) for(signed i = 0; i < format_count; i++) { + if(format[i].type == XvYUV && format[i].bits_per_pixel == 16 && format[i].format == XvPacked) { + if(format[i].component_order[0] == 'Y' && format[i].component_order[1] == 'U' + && format[i].component_order[2] == 'Y' && format[i].component_order[3] == 'V' + ) { + device.format = XvFormatYUY2; + device.fourcc = format[i].id; + break; + } + } + } + + if(device.format == XvFormatUnknown) for(signed i = 0; i < format_count; i++) { + if(format[i].type == XvYUV && format[i].bits_per_pixel == 16 && format[i].format == XvPacked) { + if(format[i].component_order[0] == 'U' && format[i].component_order[1] == 'Y' + && format[i].component_order[2] == 'V' && format[i].component_order[3] == 'Y' + ) { + device.format = XvFormatUYVY; + device.fourcc = format[i].id; + break; + } + } + } + + free(format); + if(device.format == XvFormatUnknown) { + fprintf(stderr, "VideoXv: unable to find a supported image format.\n"); + return false; + } + + device.width = 256; + device.height = 256; + + device.image = XvShmCreateImage(device.display, device.port, device.fourcc, 0, device.width, device.height, &device.shminfo); + if(!device.image) { + fprintf(stderr, "VideoXv: XShmCreateImage failed.\n"); + return false; + } + + device.shminfo.shmid = shmget(IPC_PRIVATE, device.image->data_size, IPC_CREAT | 0777); + device.shminfo.shmaddr = device.image->data = (char*)shmat(device.shminfo.shmid, 0, 0); + device.shminfo.readOnly = false; + if(!XShmAttach(device.display, &device.shminfo)) { + fprintf(stderr, "VideoXv: XShmAttach failed.\n"); + return false; + } + + buffer = new uint32_t[device.width * device.height]; + settings.width = 256; + settings.height = 256; + init_yuv_tables(); + clear(); + return true; + } + + void term() { + XShmDetach(device.display, &device.shminfo); + shmdt(device.shminfo.shmaddr); + shmctl(device.shminfo.shmid, IPC_RMID, NULL); + XFree(device.image); + + if(device.window) { + XUnmapWindow(device.display, device.window); + device.window = 0; + } + + if(device.colormap) { + XFreeColormap(device.display, device.colormap); + device.colormap = 0; + } + + if(buffer) { delete[] buffer; buffer = 0; } + if(ytable) { delete[] ytable; ytable = 0; } + if(utable) { delete[] utable; utable = 0; } + if(vtable) { delete[] vtable; vtable = 0; } + } + + void render_rgb32(unsigned width, unsigned height) { + uint32_t *input = (uint32_t*)buffer; + uint32_t *output = (uint32_t*)device.image->data; + + for(unsigned y = 0; y < height; y++) { + memcpy(output, input, width * 4); + input += device.width; + output += device.width; + } + } + + void render_rgb24(unsigned width, unsigned height) { + uint32_t *input = (uint32_t*)buffer; + uint8_t *output = (uint8_t*)device.image->data; + + for(unsigned y = 0; y < height; y++) { + for(unsigned x = 0; x < width; x++) { + uint32_t p = *input++; + *output++ = p; + *output++ = p >> 8; + *output++ = p >> 16; + } + + input += (device.width - width); + output += (device.width - width) * 3; + } + } + + void render_rgb16(unsigned width, unsigned height) { + uint32_t *input = (uint32_t*)buffer; + uint16_t *output = (uint16_t*)device.image->data; + + for(unsigned y = 0; y < height; y++) { + for(unsigned x = 0; x < width; x++) { + uint32_t p = *input++; + *output++ = ((p >> 8) & 0xf800) | ((p >> 5) & 0x07e0) | ((p >> 3) & 0x001f); //RGB32->RGB16 + } + + input += device.width - width; + output += device.width - width; + } + } + + void render_rgb15(unsigned width, unsigned height) { + uint32_t *input = (uint32_t*)buffer; + uint16_t *output = (uint16_t*)device.image->data; + + for(unsigned y = 0; y < height; y++) { + for(unsigned x = 0; x < width; x++) { + uint32_t p = *input++; + *output++ = ((p >> 9) & 0x7c00) | ((p >> 6) & 0x03e0) | ((p >> 3) & 0x001f); //RGB32->RGB15 + } + + input += device.width - width; + output += device.width - width; + } + } + + void render_yuy2(unsigned width, unsigned height) { + uint32_t *input = (uint32_t*)buffer; + uint16_t *output = (uint16_t*)device.image->data; + + for(unsigned y = 0; y < height; y++) { + for(unsigned x = 0; x < width >> 1; x++) { + uint32_t p0 = *input++; + uint32_t p1 = *input++; + p0 = ((p0 >> 8) & 0xf800) + ((p0 >> 5) & 0x07e0) + ((p0 >> 3) & 0x001f); //RGB32->RGB16 + p1 = ((p1 >> 8) & 0xf800) + ((p1 >> 5) & 0x07e0) + ((p1 >> 3) & 0x001f); //RGB32->RGB16 + + uint8_t u = (utable[p0] + utable[p1]) >> 1; + uint8_t v = (vtable[p0] + vtable[p1]) >> 1; + + *output++ = (u << 8) | ytable[p0]; + *output++ = (v << 8) | ytable[p1]; + } + + input += device.width - width; + output += device.width - width; + } + } + + void render_uyvy(unsigned width, unsigned height) { + uint32_t *input = (uint32_t*)buffer; + uint16_t *output = (uint16_t*)device.image->data; + + for(unsigned y = 0; y < height; y++) { + for(unsigned x = 0; x < width >> 1; x++) { + uint32_t p0 = *input++; + uint32_t p1 = *input++; + p0 = ((p0 >> 8) & 0xf800) + ((p0 >> 5) & 0x07e0) + ((p0 >> 3) & 0x001f); + p1 = ((p1 >> 8) & 0xf800) + ((p1 >> 5) & 0x07e0) + ((p1 >> 3) & 0x001f); + + uint8_t u = (utable[p0] + utable[p1]) >> 1; + uint8_t v = (vtable[p0] + vtable[p1]) >> 1; + + *output++ = (ytable[p0] << 8) | u; + *output++ = (ytable[p1] << 8) | v; + } + + input += device.width - width; + output += device.width - width; + } + } + + void init_yuv_tables() { + ytable = new uint8_t[65536]; + utable = new uint8_t[65536]; + vtable = new uint8_t[65536]; + + for(unsigned i = 0; i < 65536; i++) { + //extract RGB565 color data from i + uint8_t r = (i >> 11) & 31, g = (i >> 5) & 63, b = (i) & 31; + r = (r << 3) | (r >> 2); //R5->R8 + g = (g << 2) | (g >> 4); //G6->G8 + b = (b << 3) | (b >> 2); //B5->B8 + + //ITU-R Recommendation BT.601 + //double lr = 0.299, lg = 0.587, lb = 0.114; + int y = int( +(double(r) * 0.257) + (double(g) * 0.504) + (double(b) * 0.098) + 16.0 ); + int u = int( -(double(r) * 0.148) - (double(g) * 0.291) + (double(b) * 0.439) + 128.0 ); + int v = int( +(double(r) * 0.439) - (double(g) * 0.368) - (double(b) * 0.071) + 128.0 ); + + //ITU-R Recommendation BT.709 + //double lr = 0.2126, lg = 0.7152, lb = 0.0722; + //int y = int( double(r) * lr + double(g) * lg + double(b) * lb ); + //int u = int( (double(b) - y) / (2.0 - 2.0 * lb) + 128.0 ); + //int v = int( (double(r) - y) / (2.0 - 2.0 * lr) + 128.0 ); + + ytable[i] = y < 0 ? 0 : y > 255 ? 255 : y; + utable[i] = u < 0 ? 0 : u > 255 ? 255 : u; + vtable[i] = v < 0 ? 0 : v > 255 ? 255 : v; + } + } + + pVideoXv() { + device.window = 0; + device.colormap = 0; + device.port = -1; + + ytable = 0; + utable = 0; + vtable = 0; + + settings.handle = 0; + settings.synchronize = false; + } + + ~pVideoXv() { + term(); + } +}; + +DeclareVideo(Xv) + +}; diff --git a/snes/Makefile b/snes/Makefile new file mode 100755 index 00000000..d380cd8a --- /dev/null +++ b/snes/Makefile @@ -0,0 +1,58 @@ +snes_objects := snes-interface 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_objects += snes-obc1 snes-st0018 snes-sufamiturbo +snes_objects += snes-msu1 snes-link +objects += $(snes_objects) + +ifeq ($(profile),accuracy) + flags += -DPROFILE_ACCURACY + snescpu := $(snes)/cpu + snessmp := $(snes)/smp + snesdsp := $(snes)/dsp + snesppu := $(snes)/ppu +else ifeq ($(profile),compatibility) + flags += -DPROFILE_COMPATIBILITY + snescpu := $(snes)/cpu + snessmp := $(snes)/smp + snesdsp := $(snes)/alt/dsp + snesppu := $(snes)/alt/ppu-compatibility +else ifeq ($(profile),performance) + flags += -DPROFILE_PERFORMANCE + snescpu := $(snes)/alt/cpu + snessmp := $(snes)/alt/smp + snesdsp := $(snes)/alt/dsp + snesppu := $(snes)/alt/ppu-performance +endif + +obj/snes-interface.o : $(snes)/interface/interface.cpp $(call rwildcard,$(snes)/interface) +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/) +obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/) +obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/) +obj/snes-necdsp.o : $(snes)/chip/necdsp/necdsp.cpp $(call rwildcard,$(snes)/chip/necdsp/) +obj/snes-hitachidsp.o : $(snes)/chip/hitachidsp/hitachidsp.cpp $(call rwildcard,$(snes)/chip/hitachidsp/) +obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(call rwildcard,$(snes)/chip/bsx/) +obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/* +obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/* +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-sufamiturbo.o: $(snes)/chip/sufamiturbo/sufamiturbo.cpp $(snes)/chip/sufamiturbo/* +obj/snes-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/* +obj/snes-link.o : $(snes)/chip/link/link.cpp $(snes)/chip/link/* diff --git a/snes/alt/cpu/cpu.cpp b/snes/alt/cpu/cpu.cpp new file mode 100755 index 00000000..814908d0 --- /dev/null +++ b/snes/alt/cpu/cpu.cpp @@ -0,0 +1,186 @@ +#include + +#define CPU_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + CPUDebugger cpu; +#else + CPU cpu; +#endif + +#include "serialization.cpp" +#include "dma.cpp" +#include "memory.cpp" +#include "mmio.cpp" +#include "timing.cpp" + +void CPU::step(unsigned clocks) { + smp.clock -= clocks * (uint64)smp.frequency; + ppu.clock -= clocks; + for(unsigned i = 0; i < coprocessors.size(); i++) { + 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() { + if(SMP::Threaded == true) { + if(smp.clock < 0) co_switch(smp.thread); + } else { + while(smp.clock < 0) smp.enter(); + } +} + +void CPU::synchronize_ppu() { + if(PPU::Threaded == true) { + if(ppu.clock < 0) co_switch(ppu.thread); + } else { + while(ppu.clock < 0) ppu.enter(); + } +} + +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() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::CPU) { + scheduler.sync = Scheduler::SynchronizeMode::All; + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(status.nmi_pending) { + status.nmi_pending = false; + regs.vector = (regs.e == false ? 0xffea : 0xfffa); + op_irq(); + } + + if(status.irq_pending) { + status.irq_pending = false; + regs.vector = (regs.e == false ? 0xffee : 0xfffe); + op_irq(); + } + + op_step(); + } +} + +alwaysinline void CPU::op_step() { + (this->*opcode_table[op_readpc()])(); +} + +void CPU::enable() { + function read = { &CPU::mmio_read, (CPU*)&cpu }; + function write = { &CPU::mmio_write, (CPU*)&cpu }; + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write); + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write); + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write); + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write); + + read = [](unsigned addr) { return cpu.wram[addr]; }; + write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; }; + + bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000); + bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000); + bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write); +} + +void CPU::power() { + regs.a = 0x0000; + regs.x = 0x0000; + regs.y = 0x0000; + regs.s = 0x01ff; + + reset(); +} + +void CPU::reset() { + create(Enter, system.cpu_frequency()); + coprocessors.reset(); + PPUcounter::reset(); + + regs.pc = 0x000000; + regs.x.h = 0x00; + regs.y.h = 0x00; + regs.s.h = 0x01; + regs.d = 0x0000; + regs.db = 0x00; + regs.p = 0x34; + regs.e = 1; + regs.mdr = 0x00; + regs.wai = false; + update_table(); + + regs.pc.l = bus.read(0xfffc); + regs.pc.h = bus.read(0xfffd); + regs.pc.b = 0x00; + + status.nmi_valid = false; + status.nmi_line = false; + status.nmi_transition = false; + status.nmi_pending = false; + + status.irq_valid = false; + status.irq_line = false; + status.irq_transition = false; + status.irq_pending = false; + + status.irq_lock = false; + status.hdma_pending = false; + + status.wram_addr = 0x000000; + + status.joypad_strobe_latch = 0; + + status.nmi_enabled = false; + status.virq_enabled = false; + status.hirq_enabled = false; + status.auto_joypad_poll_enabled = false; + + status.pio = 0xff; + + status.htime = 0x0000; + status.vtime = 0x0000; + + status.rom_speed = 8; + + status.joy1l = status.joy1h = 0x00; + status.joy2l = status.joy2h = 0x00; + status.joy3l = status.joy3h = 0x00; + status.joy4l = status.joy4h = 0x00; + + dma_reset(); +} + +CPU::CPU() : queue(512, { &CPU::queue_event, this }) { + PPUcounter::scanline = { &CPU::scanline, this }; +} + +CPU::~CPU() { +} + +} diff --git a/snes/alt/cpu/cpu.hpp b/snes/alt/cpu/cpu.hpp new file mode 100755 index 00000000..a1953ebb --- /dev/null +++ b/snes/alt/cpu/cpu.hpp @@ -0,0 +1,157 @@ +class CPU : public Processor, public CPUcore, public PPUcounter { +public: + uint8 wram[128 * 1024]; + + enum : bool { Threaded = true }; + array coprocessors; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_smp(); + void synchronize_ppu(); + void synchronize_coprocessors(); + void synchronize_controllers(); + + uint8 pio(); + bool joylatch(); + bool interrupt_pending(); + uint8 port_read(uint8 port); + void port_write(uint8 port, uint8 data); + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + + void op_io(); + debugvirtual uint8 op_read(unsigned addr); + debugvirtual void op_write(unsigned addr, uint8 data); + + void enter(); + void enable(); + void power(); + void reset(); + + void serialize(serializer&); + CPU(); + ~CPU(); + +private: + //cpu + static void Enter(); + debugvirtual void op_step(); + + //timing + struct QueueEvent { + enum : unsigned { + DramRefresh, + HdmaRun, + }; + }; + nall::priority_queue queue; + void queue_event(unsigned id); + void last_cycle(); + void add_clocks(unsigned clocks); + void scanline(); + void run_auto_joypad_poll(); + + //memory + unsigned speed(unsigned addr) const; + + //dma + bool dma_transfer_valid(uint8 bbus, unsigned abus); + bool dma_addr_valid(unsigned abus); + uint8 dma_read(unsigned abus); + void dma_write(bool valid, unsigned addr, uint8 data); + void dma_transfer(bool direction, uint8 bbus, unsigned abus); + uint8 dma_bbus(unsigned i, unsigned index); + unsigned dma_addr(unsigned i); + unsigned hdma_addr(unsigned i); + unsigned hdma_iaddr(unsigned i); + void dma_run(); + bool hdma_active_after(unsigned i); + void hdma_update(unsigned i); + void hdma_run(); + void hdma_init(); + void dma_reset(); + + //registers + uint8 port_data[4]; + + struct Channel { + bool dma_enabled; + bool hdma_enabled; + + bool direction; + bool indirect; + bool unused; + bool reverse_transfer; + bool fixed_transfer; + uint8 transfer_mode; + + uint8 dest_addr; + uint16 source_addr; + uint8 source_bank; + + union { + uint16 transfer_size; + uint16 indirect_addr; + }; + + uint8 indirect_bank; + uint16 hdma_addr; + uint8 line_counter; + uint8 unknown; + + bool hdma_completed; + bool hdma_do_transfer; + } channel[8]; + + struct Status { + bool nmi_valid; + bool nmi_line; + bool nmi_transition; + bool nmi_pending; + + bool irq_valid; + bool irq_line; + bool irq_transition; + bool irq_pending; + + bool irq_lock; + bool hdma_pending; + + unsigned wram_addr; + + bool joypad_strobe_latch; + + bool nmi_enabled; + bool virq_enabled; + bool hirq_enabled; + bool auto_joypad_poll_enabled; + + uint8 pio; + + uint8 wrmpya; + uint8 wrmpyb; + uint16 wrdiva; + uint8 wrdivb; + + uint16 htime; + uint16 vtime; + + unsigned rom_speed; + + uint16 rddiv; + uint16 rdmpy; + + uint8 joy1l, joy1h; + uint8 joy2l, joy2h; + uint8 joy3l, joy3h; + uint8 joy4l, joy4h; + } status; + + friend class CPUDebugger; +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern CPUDebugger cpu; +#else + extern CPU cpu; +#endif diff --git a/snes/alt/cpu/debugger/debugger.cpp b/snes/alt/cpu/debugger/debugger.cpp new file mode 100755 index 00000000..59423a5d --- /dev/null +++ b/snes/alt/cpu/debugger/debugger.cpp @@ -0,0 +1,156 @@ +#ifdef CPU_CPP + +void CPUDebugger::op_step() { + bool break_event = false; + + usage[regs.pc] &= ~(UsageFlagM | UsageFlagX); + usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0); + opcode_pc = regs.pc; + + opcode_edge = true; + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); + if(step_event && step_event()) { + debugger.break_event = Debugger::BreakEvent::CPUStep; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + } + opcode_edge = false; + + CPU::op_step(); + synchronize_smp(); +} + +uint8 CPUDebugger::op_read(uint32 addr) { + uint8 data = CPU::op_read(addr); + usage[addr] |= UsageRead; + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void CPUDebugger::op_write(uint32 addr, uint8 data) { + CPU::op_write(addr, data); + usage[addr] |= UsageWrite; + usage[addr] &= ~UsageExec; + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Write, addr, data); +} + +CPUDebugger::CPUDebugger() { + usage = new uint8[1 << 24](); + opcode_pc = 0x8000; + opcode_edge = false; +} + +CPUDebugger::~CPUDebugger() { + delete[] usage; +} + +bool CPUDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //internal + item("S-CPU MDR", string("0x", hex<2>(regs.mdr))); + + //$2181-2183 + item("$2181-$2183", ""); + item("WRAM Address", string("0x", hex<6>(status.wram_addr))); + + //$4016 + item("$4016", ""); + item("Joypad Strobe Latch", status.joypad_strobe_latch); + + //$4200 + item("$4200", ""); + item("NMI Enable", status.nmi_enabled); + item("H-IRQ Enable", status.hirq_enabled); + item("V-IRQ Enable", status.virq_enabled); + item("Auto Joypad Poll", status.auto_joypad_poll_enabled); + + //$4201 + item("$4201", ""); + item("PIO", string("0x", hex<2>(status.pio))); + + //$4202 + item("$4202", ""); + item("Multiplicand", string("0x", hex<2>(status.wrmpya))); + + //$4203 + item("$4203", ""); + item("Multiplier", string("0x", hex<2>(status.wrmpyb))); + + //$4204-$4205 + item("$4204-$4205", ""); + item("Dividend", string("0x", hex<4>(status.wrdiva))); + + //$4206 + item("$4206", ""); + item("Divisor", string("0x", hex<2>(status.wrdivb))); + + //$4207-$4208 + item("$4207-$4208", ""); + item("H-Time", string("0x", hex<4>(status.htime))); + + //$4209-$420a + item("$4209-$420a", ""); + item("V-Time", string("0x", hex<4>(status.vtime))); + + //$420b + unsigned dma_enable = 0; + for(unsigned n = 0; n < 8; n++) dma_enable |= channel[n].dma_enabled << n; + + item("$420b", ""); + item("DMA Enable", string("0x", hex<2>(dma_enable))); + + //$420c + unsigned hdma_enable = 0; + for(unsigned n = 0; n < 8; n++) hdma_enable |= channel[n].hdma_enabled << n; + + item("$420c", ""); + item("HDMA Enable", string("0x", hex<2>(hdma_enable))); + + //$420d + item("$420d", ""); + item("FastROM Enable", status.rom_speed == 6); + + for(unsigned i = 0; i < 8; i++) { + item(string("DMA Channel ", i), ""); + + //$43x0 + item("Direction", channel[i].direction); + item("Indirect", channel[i].indirect); + item("Reverse Transfer", channel[i].reverse_transfer); + item("Fixed Transfer", channel[i].fixed_transfer); + item("Transfer Mode", (unsigned)channel[i].transfer_mode); + + //$43x1 + item("B-Bus Address", string("0x", hex<4>(channel[i].dest_addr))); + + //$43x2-$43x3 + item("A-Bus Address", string("0x", hex<4>(channel[i].source_addr))); + + //$43x4 + item("A-Bus Bank", string("0x", hex<2>(channel[i].source_bank))); + + //$43x5-$43x6 + item("Transfer Size / Indirect Address", string("0x", hex<4>(channel[i].transfer_size))); + + //$43x7 + item("Indirect Bank", string("0x", hex<2>(channel[i].indirect_bank))); + + //$43x8-$43x9 + item("Table Address", string("0x", hex<4>(channel[i].hdma_addr))); + + //$43xa + item("Line Counter", string("0x", hex<2>(channel[i].line_counter))); + } + + #undef item + return false; +} + +#endif diff --git a/snes/alt/cpu/debugger/debugger.hpp b/snes/alt/cpu/debugger/debugger.hpp new file mode 100755 index 00000000..31d6044f --- /dev/null +++ b/snes/alt/cpu/debugger/debugger.hpp @@ -0,0 +1,24 @@ +class CPUDebugger : public CPU, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + function step_event; + + enum Usage { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + UsageFlagM = 0x02, + UsageFlagX = 0x01, + }; + uint8 *usage; + uint32 opcode_pc; + bool opcode_edge; + + void op_step(); + uint8 op_read(uint32 addr); + void op_write(uint32 addr, uint8 data); + + CPUDebugger(); + ~CPUDebugger(); +}; diff --git a/snes/alt/cpu/dma.cpp b/snes/alt/cpu/dma.cpp new file mode 100755 index 00000000..addb6dbc --- /dev/null +++ b/snes/alt/cpu/dma.cpp @@ -0,0 +1,204 @@ +#ifdef CPU_CPP + +bool CPU::dma_transfer_valid(uint8 bbus, unsigned abus) { + //transfers from WRAM to WRAM are invalid; chip only has one address bus + if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) return false; + return true; +} + +bool CPU::dma_addr_valid(unsigned abus) { + //A-bus access to B-bus or S-CPU registers are invalid + if((abus & 0x40ff00) == 0x2100) return false; //$[00-3f|80-bf]:[2100-21ff] + if((abus & 0x40fe00) == 0x4000) return false; //$[00-3f|80-bf]:[4000-41ff] + if((abus & 0x40ffe0) == 0x4200) return false; //$[00-3f|80-bf]:[4200-421f] + if((abus & 0x40ff80) == 0x4300) return false; //$[00-3f|80-bf]:[4300-437f] + return true; +} + +uint8 CPU::dma_read(unsigned abus) { + if(dma_addr_valid(abus) == false) return 0x00; + return bus.read(abus); +} + +void CPU::dma_write(bool valid, unsigned addr, uint8 data) { + if(valid) bus.write(addr, data); +} + +void CPU::dma_transfer(bool direction, uint8 bbus, unsigned abus) { + if(direction == 0) { + uint8 data = dma_read(abus); + add_clocks(8); + dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, data); + } else { + uint8 data = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus) : 0x00; + add_clocks(8); + dma_write(dma_addr_valid(abus), abus, data); + } +} + +uint8 CPU::dma_bbus(unsigned i, unsigned index) { + switch(channel[i].transfer_mode) { default: + case 0: return (channel[i].dest_addr); //0 + case 1: return (channel[i].dest_addr + (index & 1)); //0,1 + case 2: return (channel[i].dest_addr); //0,0 + case 3: return (channel[i].dest_addr + ((index >> 1) & 1)); //0,0,1,1 + case 4: return (channel[i].dest_addr + (index & 3)); //0,1,2,3 + case 5: return (channel[i].dest_addr + (index & 1)); //0,1,0,1 + case 6: return (channel[i].dest_addr); //0,0 [2] + case 7: return (channel[i].dest_addr + ((index >> 1) & 1)); //0,0,1,1 [3] + } +} + +unsigned CPU::dma_addr(unsigned i) { + unsigned result = (channel[i].source_bank << 16) | (channel[i].source_addr); + + if(channel[i].fixed_transfer == false) { + if(channel[i].reverse_transfer == false) { + channel[i].source_addr++; + } else { + channel[i].source_addr--; + } + } + + return result; +} + +unsigned CPU::hdma_addr(unsigned i) { + return (channel[i].source_bank << 16) | (channel[i].hdma_addr++); +} + +unsigned CPU::hdma_iaddr(unsigned i) { + return (channel[i].indirect_bank << 16) | (channel[i].indirect_addr++); +} + +void CPU::dma_run() { + add_clocks(16); + + for(unsigned i = 0; i < 8; i++) { + if(channel[i].dma_enabled == false) continue; + add_clocks(8); + + unsigned index = 0; + do { + dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i)); + } while(channel[i].dma_enabled && --channel[i].transfer_size); + + channel[i].dma_enabled = false; + } + + status.irq_lock = true; +} + +bool CPU::hdma_active_after(unsigned i) { + for(unsigned n = i + 1; i < 8; i++) { + if(channel[i].hdma_enabled && !channel[i].hdma_completed) return true; + } + return false; +} + +void CPU::hdma_update(unsigned i) { + if((channel[i].line_counter & 0x7f) == 0) { + channel[i].line_counter = dma_read(hdma_addr(i)); + channel[i].hdma_completed = (channel[i].line_counter == 0); + channel[i].hdma_do_transfer = !channel[i].hdma_completed; + add_clocks(8); + + if(channel[i].indirect) { + channel[i].indirect_addr = dma_read(hdma_addr(i)) << 8; + add_clocks(8); + + //emulating this glitch causes a slight slowdown; only enable if needed + //if(!channel[i].hdma_completed || hdma_active_after(i)) { + channel[i].indirect_addr >>= 8; + channel[i].indirect_addr |= dma_read(hdma_addr(i)) << 8; + add_clocks(8); + //} + } + } +} + +void CPU::hdma_run() { + unsigned channels = 0; + for(unsigned i = 0; i < 8; i++) { + if(channel[i].hdma_enabled) channels++; + } + if(channels == 0) return; + + add_clocks(16); + for(unsigned i = 0; i < 8; i++) { + if(channel[i].hdma_enabled == false || channel[i].hdma_completed == true) continue; + channel[i].dma_enabled = false; + + if(channel[i].hdma_do_transfer) { + static const unsigned transfer_length[] = { 1, 2, 2, 4, 4, 4, 2, 4 }; + unsigned length = transfer_length[channel[i].transfer_mode]; + for(unsigned index = 0; index < length; index++) { + unsigned addr = channel[i].indirect == false ? hdma_addr(i) : hdma_iaddr(i); + dma_transfer(channel[i].direction, dma_bbus(i, index), addr); + } + } + } + + for(unsigned i = 0; i < 8; i++) { + if(channel[i].hdma_enabled == false || channel[i].hdma_completed == true) continue; + + channel[i].line_counter--; + channel[i].hdma_do_transfer = channel[i].line_counter & 0x80; + hdma_update(i); + } + + status.irq_lock = true; +} + +void CPU::hdma_init() { + unsigned channels = 0; + for(unsigned i = 0; i < 8; i++) { + channel[i].hdma_completed = false; + channel[i].hdma_do_transfer = false; + if(channel[i].hdma_enabled) channels++; + } + if(channels == 0) return; + + add_clocks(16); + for(unsigned i = 0; i < 8; i++) { + if(!channel[i].hdma_enabled) continue; + channel[i].dma_enabled = false; + + channel[i].hdma_addr = channel[i].source_addr; + channel[i].line_counter = 0; + hdma_update(i); + } + + status.irq_lock = true; +} + +void CPU::dma_reset() { + for(unsigned i = 0; i < 8; i++) { + channel[i].dma_enabled = false; + channel[i].hdma_enabled = false; + + channel[i].direction = 1; + channel[i].indirect = true; + channel[i].unused = true; + channel[i].reverse_transfer = true; + channel[i].fixed_transfer = true; + channel[i].transfer_mode = 0x07; + + channel[i].dest_addr = 0xff; + channel[i].source_addr = 0xffff; + channel[i].source_bank = 0xff; + + channel[i].transfer_size = 0xffff; + channel[i].indirect_addr = 0xffff; + + channel[i].indirect_bank = 0xff; + channel[i].hdma_addr = 0xff; + channel[i].line_counter = 0xff; + channel[i].unknown = 0xff; + + channel[i].hdma_completed = false; + channel[i].hdma_do_transfer = false; + } +} + +#endif diff --git a/snes/alt/cpu/memory.cpp b/snes/alt/cpu/memory.cpp new file mode 100755 index 00000000..fed9870a --- /dev/null +++ b/snes/alt/cpu/memory.cpp @@ -0,0 +1,48 @@ +#ifdef CPU_CPP + +uint8 CPU::pio() { + return status.pio; +} + +bool CPU::joylatch() { + return status.joypad_strobe_latch; +} + +bool CPU::interrupt_pending() { + return false; +} + +uint8 CPU::port_read(uint8 port) { + return port_data[port & 3]; +} + +void CPU::port_write(uint8 port, uint8 data) { + port_data[port & 3] = data; +} + +void CPU::op_io() { + add_clocks(6); +} + +uint8 CPU::op_read(unsigned addr) { + regs.mdr = bus.read(addr); + add_clocks(speed(addr)); + return regs.mdr; +} + +void CPU::op_write(unsigned addr, uint8 data) { + add_clocks(speed(addr)); + bus.write(addr, regs.mdr = data); +} + +unsigned CPU::speed(unsigned addr) const { + if(addr & 0x408000) { + if(addr & 0x800000) return status.rom_speed; + return 8; + } + if((addr + 0x6000) & 0x4000) return 8; + if((addr - 0x4000) & 0x7e00) return 6; + return 12; +} + +#endif diff --git a/snes/alt/cpu/mmio.cpp b/snes/alt/cpu/mmio.cpp new file mode 100755 index 00000000..09bd7bc0 --- /dev/null +++ b/snes/alt/cpu/mmio.cpp @@ -0,0 +1,303 @@ +#ifdef CPU_CPP + +uint8 CPU::mmio_read(unsigned addr) { + if((addr & 0xffc0) == 0x2140) { + synchronize_smp(); + return smp.port_read(addr & 3); + } + + switch(addr & 0xffff) { + case 0x2180: { + uint8 result = bus.read(0x7e0000 | status.wram_addr); + status.wram_addr = (status.wram_addr + 1) & 0x01ffff; + return result; + } + + case 0x4016: { + uint8 result = regs.mdr & 0xfc; + result |= input.port1->data() & 3; + return result; + } + + case 0x4017: { + uint8 result = (regs.mdr & 0xe0) | 0x1c; + result |= input.port2->data() & 3; + return result; + } + + case 0x4210: { + uint8 result = (regs.mdr & 0x70); + result |= status.nmi_line << 7; + result |= 0x02; //CPU revision + status.nmi_line = false; + return result; + } + + case 0x4211: { + uint8 result = (regs.mdr & 0x7f); + result |= status.irq_line << 7; + status.irq_line = false; + return result; + } + + case 0x4212: { + uint8 result = (regs.mdr & 0x3e); + unsigned vbstart = ppu.overscan() == false ? 225 : 240; + + if(vcounter() >= vbstart && vcounter() <= vbstart + 2) result |= 0x01; + if(hcounter() <= 2 || hcounter() >= 1096) result |= 0x40; + if(vcounter() >= vbstart) result |= 0x80; + + return result; + } + + case 0x4213: return status.pio; + + case 0x4214: return status.rddiv >> 0; + case 0x4215: return status.rddiv >> 8; + case 0x4216: return status.rdmpy >> 0; + case 0x4217: return status.rdmpy >> 8; + + case 0x4218: return status.joy1l; + case 0x4219: return status.joy1h; + case 0x421a: return status.joy2l; + case 0x421b: return status.joy2h; + case 0x421c: return status.joy3l; + case 0x421d: return status.joy3h; + case 0x421e: return status.joy4l; + case 0x421f: return status.joy4h; + } + + if((addr & 0xff80) == 0x4300) { + unsigned i = (addr >> 4) & 7; + switch(addr & 0xff8f) { + case 0x4300: { + return (channel[i].direction << 7) + | (channel[i].indirect << 6) + | (channel[i].unused << 5) + | (channel[i].reverse_transfer << 4) + | (channel[i].fixed_transfer << 3) + | (channel[i].transfer_mode << 0); + } + + case 0x4301: return channel[i].dest_addr; + case 0x4302: return channel[i].source_addr >> 0; + case 0x4303: return channel[i].source_addr >> 8; + case 0x4304: return channel[i].source_bank; + case 0x4305: return channel[i].transfer_size >> 0; + case 0x4306: return channel[i].transfer_size >> 8; + case 0x4307: return channel[i].indirect_bank; + case 0x4308: return channel[i].hdma_addr >> 0; + case 0x4309: return channel[i].hdma_addr >> 8; + case 0x430a: return channel[i].line_counter; + case 0x430b: case 0x430f: return channel[i].unknown; + } + } + + return regs.mdr; +} + +void CPU::mmio_write(unsigned addr, uint8 data) { + if((addr & 0xffc0) == 0x2140) { + synchronize_smp(); + port_write(addr & 3, data); + return; + } + + switch(addr & 0xffff) { + case 0x2180: { + bus.write(0x7e0000 | status.wram_addr, data); + status.wram_addr = (status.wram_addr + 1) & 0x01ffff; + return; + } + + case 0x2181: { + status.wram_addr = (status.wram_addr & 0x01ff00) | (data << 0); + return; + } + + case 0x2182: { + status.wram_addr = (status.wram_addr & 0x0100ff) | (data << 8); + return; + } + + case 0x2183: { + status.wram_addr = (status.wram_addr & 0x00ffff) | ((data & 1) << 16); + return; + } + + case 0x4016: { + input.port1->latch(data & 1); + input.port2->latch(data & 1); + return; + } + + case 0x4200: { + bool nmi_enabled = status.nmi_enabled; + bool virq_enabled = status.virq_enabled; + bool hirq_enabled = status.hirq_enabled; + + status.nmi_enabled = data & 0x80; + status.virq_enabled = data & 0x20; + status.hirq_enabled = data & 0x10; + status.auto_joypad_poll_enabled = data & 0x01; + + if(!nmi_enabled && status.nmi_enabled && status.nmi_line) { + status.nmi_transition = true; + } + + if(status.virq_enabled && !status.hirq_enabled && status.irq_line) { + status.irq_transition = true; + } + + if(!status.virq_enabled && !status.hirq_enabled) { + status.irq_line = false; + status.irq_transition = false; + } + + status.irq_lock = true; + return; + } + + case 0x4201: { + if((status.pio & 0x80) && !(data & 0x80)) ppu.latch_counters(); + status.pio = data; + } + + case 0x4202: { + status.wrmpya = data; + return; + } + + case 0x4203: { + status.wrmpyb = data; + status.rdmpy = status.wrmpya * status.wrmpyb; + return; + } + + case 0x4204: { + status.wrdiva = (status.wrdiva & 0xff00) | (data << 0); + return; + } + + case 0x4205: { + status.wrdiva = (data << 8) | (status.wrdiva & 0x00ff); + return; + } + + case 0x4206: { + status.wrdivb = data; + status.rddiv = status.wrdivb ? status.wrdiva / status.wrdivb : 0xffff; + status.rdmpy = status.wrdivb ? status.wrdiva % status.wrdivb : status.wrdiva; + return; + } + + case 0x4207: { + status.htime = (status.htime & 0x0100) | (data << 0); + return; + } + + case 0x4208: { + status.htime = ((data & 1) << 8) | (status.htime & 0x00ff); + return; + } + + case 0x4209: { + status.vtime = (status.vtime & 0x0100) | (data << 0); + return; + } + + case 0x420a: { + status.vtime = ((data & 1) << 8) | (status.vtime & 0x00ff); + return; + } + + case 0x420b: { + for(unsigned i = 0; i < 8; i++) channel[i].dma_enabled = data & (1 << i); + if(data) dma_run(); + return; + } + + case 0x420c: { + for(unsigned i = 0; i < 8; i++) channel[i].hdma_enabled = data & (1 << i); + return; + } + + case 0x420d: { + status.rom_speed = data & 1 ? 6 : 8; + return; + } + } + + if((addr & 0xff80) == 0x4300) { + unsigned i = (addr >> 4) & 7; + switch(addr & 0xff8f) { + case 0x4300: { + channel[i].direction = data & 0x80; + channel[i].indirect = data & 0x40; + channel[i].unused = data & 0x20; + channel[i].reverse_transfer = data & 0x10; + channel[i].fixed_transfer = data & 0x08; + channel[i].transfer_mode = data & 0x07; + return; + } + + case 0x4301: { + channel[i].dest_addr = data; + return; + } + + case 0x4302: { + channel[i].source_addr = (channel[i].source_addr & 0xff00) | (data << 0); + return; + } + + case 0x4303: { + channel[i].source_addr = (data << 8) | (channel[i].source_addr & 0x00ff); + return; + } + + case 0x4304: { + channel[i].source_bank = data; + return; + } + + case 0x4305: { + channel[i].transfer_size = (channel[i].transfer_size & 0xff00) | (data << 0); + return; + } + + case 0x4306: { + channel[i].transfer_size = (data << 8) | (channel[i].transfer_size & 0x00ff); + return; + } + + case 0x4307: { + channel[i].indirect_bank = data; + return; + } + + case 0x4308: { + channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data << 0); + return; + } + + case 0x4309: { + channel[i].hdma_addr = (data << 8) | (channel[i].hdma_addr & 0x00ff); + return; + } + + case 0x430a: { + channel[i].line_counter = data; + return; + } + + case 0x430b: case 0x430f: { + channel[i].unknown = data; + return; + } + } + } +} + +#endif diff --git a/snes/alt/cpu/serialization.cpp b/snes/alt/cpu/serialization.cpp new file mode 100755 index 00000000..2f7a3c90 --- /dev/null +++ b/snes/alt/cpu/serialization.cpp @@ -0,0 +1,86 @@ +#ifdef CPU_CPP + +void CPU::serialize(serializer &s) { + Processor::serialize(s); + CPUcore::core_serialize(s); + PPUcounter::serialize(s); + + s.array(wram); + + queue.serialize(s); + s.array(port_data); + + for(unsigned i = 0; i < 8; i++) { + s.integer(channel[i].dma_enabled); + s.integer(channel[i].hdma_enabled); + + s.integer(channel[i].direction); + s.integer(channel[i].indirect); + s.integer(channel[i].unused); + s.integer(channel[i].reverse_transfer); + s.integer(channel[i].fixed_transfer); + s.integer(channel[i].transfer_mode); + + s.integer(channel[i].dest_addr); + s.integer(channel[i].source_addr); + s.integer(channel[i].source_bank); + + s.integer(channel[i].transfer_size); + + s.integer(channel[i].indirect_bank); + s.integer(channel[i].hdma_addr); + s.integer(channel[i].line_counter); + s.integer(channel[i].unknown); + + s.integer(channel[i].hdma_completed); + s.integer(channel[i].hdma_do_transfer); + } + + s.integer(status.nmi_valid); + s.integer(status.nmi_line); + s.integer(status.nmi_transition); + s.integer(status.nmi_pending); + + s.integer(status.irq_valid); + s.integer(status.irq_line); + s.integer(status.irq_transition); + s.integer(status.irq_pending); + + s.integer(status.irq_lock); + s.integer(status.hdma_pending); + + s.integer(status.wram_addr); + + s.integer(status.joypad_strobe_latch); + + s.integer(status.nmi_enabled); + s.integer(status.virq_enabled); + s.integer(status.hirq_enabled); + s.integer(status.auto_joypad_poll_enabled); + + s.integer(status.pio); + + s.integer(status.wrmpya); + s.integer(status.wrmpyb); + s.integer(status.wrdiva); + s.integer(status.wrdivb); + + s.integer(status.htime); + s.integer(status.vtime); + + s.integer(status.rom_speed); + + s.integer(status.rddiv); + s.integer(status.rdmpy); + + s.integer(status.joy1l); + s.integer(status.joy1h); + s.integer(status.joy2l); + s.integer(status.joy2h); + s.integer(status.joy3l); + s.integer(status.joy3h); + s.integer(status.joy4l); + s.integer(status.joy4h); +} + +#endif diff --git a/snes/alt/cpu/timing.cpp b/snes/alt/cpu/timing.cpp new file mode 100755 index 00000000..88577db2 --- /dev/null +++ b/snes/alt/cpu/timing.cpp @@ -0,0 +1,119 @@ +#ifdef CPU_CPP + +void CPU::queue_event(unsigned id) { + switch(id) { + case QueueEvent::DramRefresh: return add_clocks(40); + case QueueEvent::HdmaRun: return hdma_run(); + } +} + +void CPU::last_cycle() { + if(status.irq_lock) { + status.irq_lock = false; + return; + } + + if(status.nmi_transition) { + regs.wai = false; + status.nmi_transition = false; + status.nmi_pending = true; + } + + if(status.irq_transition || regs.irq) { + regs.wai = false; + status.irq_transition = false; + status.irq_pending = !regs.p.i; + } +} + +void CPU::add_clocks(unsigned clocks) { + if(status.hirq_enabled) { + if(status.virq_enabled) { + unsigned cpu_time = vcounter() * 1364 + hcounter(); + unsigned irq_time = status.vtime * 1364 + status.htime * 4; + unsigned framelines = (system.region() == System::Region::NTSC ? 262 : 312) + field(); + if(cpu_time > irq_time) irq_time += framelines * 1364; + bool irq_valid = status.irq_valid; + status.irq_valid = cpu_time <= irq_time && cpu_time + clocks > irq_time; + if(!irq_valid && status.irq_valid) status.irq_line = true; + } else { + unsigned irq_time = status.htime * 4; + if(hcounter() > irq_time) irq_time += 1364; + bool irq_valid = status.irq_valid; + status.irq_valid = hcounter() <= irq_time && hcounter() + clocks > irq_time; + if(!irq_valid && status.irq_valid) status.irq_line = true; + } + if(status.irq_line) status.irq_transition = true; + } else if(status.virq_enabled) { + bool irq_valid = status.irq_valid; + status.irq_valid = vcounter() == status.vtime; + if(!irq_valid && status.irq_valid) status.irq_line = true; + if(status.irq_line) status.irq_transition = true; + } else { + status.irq_valid = false; + } + + tick(clocks); + queue.tick(clocks); + step(clocks); +} + +void CPU::scanline() { + synchronize_smp(); + synchronize_ppu(); + synchronize_coprocessors(); + system.scanline(); + + if(vcounter() == 0) hdma_init(); + + queue.enqueue(534, QueueEvent::DramRefresh); + + if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) { + queue.enqueue(1104 + 8, QueueEvent::HdmaRun); + } + + bool nmi_valid = status.nmi_valid; + status.nmi_valid = vcounter() >= (ppu.overscan() == false ? 225 : 240); + if(!nmi_valid && status.nmi_valid) { + status.nmi_line = true; + if(status.nmi_enabled) status.nmi_transition = true; + } else if(nmi_valid && !status.nmi_valid) { + status.nmi_line = false; + } + + if(status.auto_joypad_poll_enabled && vcounter() == (ppu.overscan() == false ? 227 : 242)) { + 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.port1->data(); + uint8 port1 = input.port2->data(); + + joy1 |= (port0 & 1) ? (0x8000 >> i) : 0; + joy2 |= (port1 & 1) ? (0x8000 >> i) : 0; + joy3 |= (port0 & 2) ? (0x8000 >> i) : 0; + joy4 |= (port1 & 2) ? (0x8000 >> i) : 0; + } + + status.joy1l = joy1; + status.joy1h = joy1 >> 8; + + status.joy2l = joy2; + status.joy2h = joy2 >> 8; + + status.joy3l = joy3; + status.joy3h = joy3 >> 8; + + status.joy4l = joy4; + status.joy4h = joy4 >> 8; +} + +#endif diff --git a/snes/alt/dsp/SPC_DSP.cpp b/snes/alt/dsp/SPC_DSP.cpp new file mode 100755 index 00000000..b0121407 --- /dev/null +++ b/snes/alt/dsp/SPC_DSP.cpp @@ -0,0 +1,1027 @@ +// snes_spc 0.9.0. http://www.slack.net/~ant/ + +#include "SPC_DSP.h" + +#include "blargg_endian.h" +#include + +/* Copyright (C) 2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +#ifdef BLARGG_ENABLE_OPTIMIZER + #include BLARGG_ENABLE_OPTIMIZER +#endif + +#if INT_MAX < 0x7FFFFFFF + #error "Requires that int type have at least 32 bits" +#endif + +// TODO: add to blargg_endian.h +#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr )) +#define GET_LE16A( addr ) GET_LE16( addr ) +#define SET_LE16A( addr, data ) SET_LE16( addr, data ) + +static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + +// 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, +// 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, +// 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, +// 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, +// 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, +// 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x9C,0x4E,0x7B,0xFF, +// 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, +// 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF +}; + +// if ( io < -32768 ) io = -32768; +// if ( io > 32767 ) io = 32767; +#define CLAMP16( io )\ +{\ + if ( (int16_t) io != io )\ + io = (io >> 31) ^ 0x7FFF;\ +} + +// Access global DSP register +#define REG(n) m.regs [r_##n] + +// Access voice DSP register +#define VREG(r,n) r [v_##n] + +#define WRITE_SAMPLES( l, r, out ) \ +{\ + out [0] = l;\ + out [1] = r;\ + out += 2;\ + if ( out >= m.out_end )\ + {\ + check( out == m.out_end );\ + check( m.out_end != &m.extra [extra_size] || \ + (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\ + out = m.extra;\ + m.out_end = &m.extra [extra_size];\ + }\ +}\ + +void SPC_DSP::set_output( sample_t* out, int size ) +{ + require( (size & 1) == 0 ); // must be even + if ( !out ) + { + out = m.extra; + size = extra_size; + } + m.out_begin = out; + m.out = out; + m.out_end = out + size; +} + +// Volume registers and efb are signed! Easy to forget int8_t cast. +// Prefixes are to avoid accidental use of locals with same names. + +// Gaussian interpolation + +static short const gauss [512] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, +1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, +1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, +1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, +1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, +1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, +1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, +1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, +}; + +inline int SPC_DSP::interpolate( voice_t const* v ) +{ + // Make pointers into gaussian based on fractional position between samples + int offset = v->interp_pos >> 4 & 0xFF; + short const* fwd = gauss + 255 - offset; + short const* rev = gauss + offset; // mirror left half of gaussian + + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + int out; + out = (fwd [ 0] * in [0]) >> 11; + out += (fwd [256] * in [1]) >> 11; + out += (rev [256] * in [2]) >> 11; + out = (int16_t) out; + out += (rev [ 0] * in [3]) >> 11; + + CLAMP16( out ); + out &= ~1; + return out; +} + + +//// Counters + +int const simple_counter_range = 2048 * 5 * 3; // 30720 + +static unsigned const counter_rates [32] = +{ + simple_counter_range + 1, // never fires + 2048, 1536, + 1280, 1024, 768, + 640, 512, 384, + 320, 256, 192, + 160, 128, 96, + 80, 64, 48, + 40, 32, 24, + 20, 16, 12, + 10, 8, 6, + 5, 4, 3, + 2, + 1 +}; + +static unsigned const counter_offsets [32] = +{ + 1, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 0, + 0 +}; + +inline void SPC_DSP::init_counter() +{ + m.counter = 0; +} + +inline void SPC_DSP::run_counters() +{ + if ( --m.counter < 0 ) + m.counter = simple_counter_range - 1; +} + +inline unsigned SPC_DSP::read_counter( int rate ) +{ + return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; +} + + +//// Envelope + +inline void SPC_DSP::run_envelope( voice_t* const v ) +{ + int env = v->env; + if ( v->env_mode == env_release ) // 60% + { + if ( (env -= 0x8) < 0 ) + env = 0; + v->env = env; + } + else + { + int rate; + int env_data = VREG(v->regs,adsr1); + if ( m.t_adsr0 & 0x80 ) // 99% ADSR + { + if ( v->env_mode >= env_decay ) // 99% + { + env--; + env -= env >> 8; + rate = env_data & 0x1F; + if ( v->env_mode == env_decay ) // 1% + rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; + } + else // env_attack + { + rate = (m.t_adsr0 & 0x0F) * 2 + 1; + env += rate < 31 ? 0x20 : 0x400; + } + } + else // GAIN + { + int mode; + env_data = VREG(v->regs,gain); + mode = env_data >> 5; + if ( mode < 4 ) // direct + { + env = env_data * 0x10; + rate = 31; + } + else + { + rate = env_data & 0x1F; + if ( mode == 4 ) // 4: linear decrease + { + env -= 0x20; + } + else if ( mode < 6 ) // 5: exponential decrease + { + env--; + env -= env >> 8; + } + else // 6,7: linear increase + { + env += 0x20; + if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) + env += 0x8 - 0x20; // 7: two-slope linear increase + } + } + } + + // Sustain level + if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) + v->env_mode = env_sustain; + + v->hidden_env = env; + + // unsigned cast because linear decrease going negative also triggers this + if ( (unsigned) env > 0x7FF ) + { + env = (env < 0 ? 0 : 0x7FF); + if ( v->env_mode == env_attack ) + v->env_mode = env_decay; + } + + if ( !read_counter( rate ) ) + v->env = env; // nothing else is controlled by the counter + } +} + + +//// BRR Decoding + +inline void SPC_DSP::decode_brr( voice_t* v ) +{ + // Arrange the four input nybbles in 0xABCD order for easy decoding + int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; + + int const header = m.t_brr_header; + + // Write to next four samples in circular buffer + int* pos = &v->buf [v->buf_pos]; + int* end; + if ( (v->buf_pos += 4) >= brr_buf_size ) + v->buf_pos = 0; + + // Decode four samples + for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) + { + // Extract nybble and sign-extend + int s = (int16_t) nybbles >> 12; + + // Shift sample based on header + int const shift = header >> 4; + s = (s << shift) >> 1; + if ( shift >= 0xD ) // handle invalid range + s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) + + // Apply IIR filter (8 is the most commonly used) + int const filter = header & 0x0C; + int const p1 = pos [brr_buf_size - 1]; + int const p2 = pos [brr_buf_size - 2] >> 1; + if ( filter >= 8 ) + { + s += p1; + s -= p2; + if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 + { + s += p2 >> 4; + s += (p1 * -3) >> 6; + } + else // s += p1 * 0.8984375 - p2 * 0.40625 + { + s += (p1 * -13) >> 7; + s += (p2 * 3) >> 4; + } + } + else if ( filter ) // s += p1 * 0.46875 + { + s += p1 >> 1; + s += (-p1) >> 5; + } + + // Adjust and write sample + CLAMP16( s ); + s = (int16_t) (s * 2); + pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around + } +} + + +//// Misc + +#define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n() + +MISC_CLOCK( 27 ) +{ + m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON +} +MISC_CLOCK( 28 ) +{ + m.t_non = REG(non); + m.t_eon = REG(eon); + m.t_dir = REG(dir); +} +MISC_CLOCK( 29 ) +{ + if ( (m.every_other_sample ^= 1) != 0 ) + m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read +} +MISC_CLOCK( 30 ) +{ + if ( m.every_other_sample ) + { + m.kon = m.new_kon; + m.t_koff = REG(koff) | m.mute_mask; + } + + run_counters(); + + // Noise + if ( !read_counter( REG(flg) & 0x1F ) ) + { + int feedback = (m.noise << 13) ^ (m.noise << 14); + m.noise = (feedback & 0x4000) ^ (m.noise >> 1); + } +} + + +//// Voices + +#define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v ) + +inline VOICE_CLOCK( V1 ) +{ + m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; + m.t_srcn = VREG(v->regs,srcn); +} +inline VOICE_CLOCK( V2 ) +{ + // Read sample pointer (ignored if not needed) + uint8_t const* entry = &m.ram [m.t_dir_addr]; + if ( !v->kon_delay ) + entry += 2; + m.t_brr_next_addr = GET_LE16A( entry ); + + m.t_adsr0 = VREG(v->regs,adsr0); + + // Read pitch, spread over two clocks + m.t_pitch = VREG(v->regs,pitchl); +} +inline VOICE_CLOCK( V3a ) +{ + m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; +} +inline VOICE_CLOCK( V3b ) +{ + // Read BRR header and byte + m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; + m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking +} +VOICE_CLOCK( V3c ) +{ + // Pitch modulation using previous voice's output + if ( m.t_pmon & v->vbit ) + m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; + + if ( v->kon_delay ) + { + // Get ready to start BRR decoding on next sample + if ( v->kon_delay == 5 ) + { + v->brr_addr = m.t_brr_next_addr; + v->brr_offset = 1; + v->buf_pos = 0; + m.t_brr_header = 0; // header is ignored on this sample + m.kon_check = true; + } + + // Envelope is never run during KON + v->env = 0; + v->hidden_env = 0; + + // Disable BRR decoding until last three samples + v->interp_pos = 0; + if ( --v->kon_delay & 3 ) + v->interp_pos = 0x4000; + + // Pitch is never added during KON + m.t_pitch = 0; + } + + // Gaussian interpolation + { + int output = interpolate( v ); + + // Noise + if ( m.t_non & v->vbit ) + output = (int16_t) (m.noise * 2); + + // Apply envelope + m.t_output = (output * v->env) >> 11 & ~1; + v->t_envx_out = (uint8_t) (v->env >> 4); + } + + // Immediate silence due to end of sample or soft reset + if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) + { + v->env_mode = env_release; + v->env = 0; + } + + if ( m.every_other_sample ) + { + // KOFF + if ( m.t_koff & v->vbit ) + v->env_mode = env_release; + + // KON + if ( m.kon & v->vbit ) + { + v->kon_delay = 5; + v->env_mode = env_attack; + } + } + + // Run envelope for next sample + if ( !v->kon_delay ) + run_envelope( v ); +} +inline void SPC_DSP::voice_output( voice_t const* v, int ch ) +{ + // Apply left/right volume + int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; + + // Add to output total + m.t_main_out [ch] += amp; + CLAMP16( m.t_main_out [ch] ); + + // Optionally add to echo total + if ( m.t_eon & v->vbit ) + { + m.t_echo_out [ch] += amp; + CLAMP16( m.t_echo_out [ch] ); + } +} +VOICE_CLOCK( V4 ) +{ + // Decode BRR + m.t_looped = 0; + if ( v->interp_pos >= 0x4000 ) + { + decode_brr( v ); + + if ( (v->brr_offset += 2) >= brr_block_size ) + { + // Start decoding next BRR block + assert( v->brr_offset == brr_block_size ); + v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; + if ( m.t_brr_header & 1 ) + { + v->brr_addr = m.t_brr_next_addr; + m.t_looped = v->vbit; + } + v->brr_offset = 1; + } + } + + // Apply pitch + v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; + + // Keep from getting too far ahead (when using pitch modulation) + if ( v->interp_pos > 0x7FFF ) + v->interp_pos = 0x7FFF; + + // Output left + voice_output( v, 0 ); +} +inline VOICE_CLOCK( V5 ) +{ + // Output right + voice_output( v, 1 ); + + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier + int endx_buf = REG(endx) | m.t_looped; + + // Clear bit in ENDX if KON just began + if ( v->kon_delay == 5 ) + endx_buf &= ~v->vbit; + m.endx_buf = (uint8_t) endx_buf; +} +inline VOICE_CLOCK( V6 ) +{ + (void) v; // avoid compiler warning about unused v + m.outx_buf = (uint8_t) (m.t_output >> 8); +} +inline VOICE_CLOCK( V7 ) +{ + // Update ENDX + REG(endx) = m.endx_buf; + + m.envx_buf = v->t_envx_out; +} +inline VOICE_CLOCK( V8 ) +{ + // Update OUTX + VREG(v->regs,outx) = m.outx_buf; +} +inline VOICE_CLOCK( V9 ) +{ + // Update ENVX + VREG(v->regs,envx) = m.envx_buf; +} + +// Most voices do all these in one clock, so make a handy composite +inline VOICE_CLOCK( V3 ) +{ + voice_V3a( v ); + voice_V3b( v ); + voice_V3c( v ); +} + +// Common combinations of voice steps on different voices. This greatly reduces +// code size and allows everything to be inlined in these functions. +VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } +VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } +VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } + + +//// Echo + +// Current echo buffer pointer for left/right channel +#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2]) + +// Sample in echo history buffer, where 0 is the oldest +#define ECHO_FIR( i ) (m.echo_hist_pos [i]) + +// Calculate FIR point for left/right channel +#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6) + +#define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() + +inline void SPC_DSP::echo_read( int ch ) +{ + int s = GET_LE16SA( ECHO_PTR( ch ) ); + // second copy simplifies wrap-around handling + ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; +} + +ECHO_CLOCK( 22 ) +{ + // History + if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) + m.echo_hist_pos = m.echo_hist; + + m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; + echo_read( 0 ); + + // FIR (using l and r temporaries below helps compiler optimize) + int l = CALC_FIR( 0, 0 ); + int r = CALC_FIR( 0, 1 ); + + m.t_echo_in [0] = l; + m.t_echo_in [1] = r; +} +ECHO_CLOCK( 23 ) +{ + int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); + int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); + + m.t_echo_in [0] += l; + m.t_echo_in [1] += r; + + echo_read( 1 ); +} +ECHO_CLOCK( 24 ) +{ + int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); + int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); + + m.t_echo_in [0] += l; + m.t_echo_in [1] += r; +} +ECHO_CLOCK( 25 ) +{ + int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); + int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); + + l = (int16_t) l; + r = (int16_t) r; + + l += (int16_t) CALC_FIR( 7, 0 ); + r += (int16_t) CALC_FIR( 7, 1 ); + + CLAMP16( l ); + CLAMP16( r ); + + m.t_echo_in [0] = l & ~1; + m.t_echo_in [1] = r & ~1; +} +inline int SPC_DSP::echo_output( int ch ) +{ + int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + + (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); + CLAMP16( out ); + return out; +} +ECHO_CLOCK( 26 ) +{ + // Left output volumes + // (save sample for next clock so we can output both together) + m.t_main_out [0] = echo_output( 0 ); + + // Echo feedback + int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); + int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); + + CLAMP16( l ); + CLAMP16( r ); + + m.t_echo_out [0] = l & ~1; + m.t_echo_out [1] = r & ~1; +} +ECHO_CLOCK( 27 ) +{ + // Output + int l = m.t_main_out [0]; + int r = echo_output( 1 ); + m.t_main_out [0] = 0; + m.t_main_out [1] = 0; + + // TODO: global muting isn't this simple (turns DAC on and off + // or something, causing small ~37-sample pulse when first muted) + if ( REG(flg) & 0x40 ) + { + l = 0; + r = 0; + } + + // Output sample to DAC + #ifdef SPC_DSP_OUT_HOOK + SPC_DSP_OUT_HOOK( l, r ); + #else + sample_t* out = m.out; + WRITE_SAMPLES( l, r, out ); + m.out = out; + #endif +} +ECHO_CLOCK( 28 ) +{ + m.t_echo_enabled = REG(flg); +} +inline void SPC_DSP::echo_write( int ch ) +{ + if ( !(m.t_echo_enabled & 0x20) ) + SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); + m.t_echo_out [ch] = 0; +} +ECHO_CLOCK( 29 ) +{ + m.t_esa = REG(esa); + + if ( !m.echo_offset ) + m.echo_length = (REG(edl) & 0x0F) * 0x800; + + m.echo_offset += 4; + if ( m.echo_offset >= m.echo_length ) + m.echo_offset = 0; + + // Write left echo + echo_write( 0 ); + + m.t_echo_enabled = REG(flg); +} +ECHO_CLOCK( 30 ) +{ + // Write right echo + echo_write( 1 ); +} + + +//// Timing + +// Execute clock for a particular voice +#define V( clock, voice ) voice_##clock( &m.voices [voice] ); + +/* The most common sequence of clocks uses composite operations +for efficiency. For example, the following are equivalent to the +individual steps on the right: + +V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5) +V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4) +V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */ + +// Voice 0 1 2 3 4 5 6 7 +#define GEN_DSP_TIMING \ +PHASE( 0) V(V5,0)V(V2,1)\ +PHASE( 1) V(V6,0)V(V3,1)\ +PHASE( 2) V(V7_V4_V1,0)\ +PHASE( 3) V(V8_V5_V2,0)\ +PHASE( 4) V(V9_V6_V3,0)\ +PHASE( 5) V(V7_V4_V1,1)\ +PHASE( 6) V(V8_V5_V2,1)\ +PHASE( 7) V(V9_V6_V3,1)\ +PHASE( 8) V(V7_V4_V1,2)\ +PHASE( 9) V(V8_V5_V2,2)\ +PHASE(10) V(V9_V6_V3,2)\ +PHASE(11) V(V7_V4_V1,3)\ +PHASE(12) V(V8_V5_V2,3)\ +PHASE(13) V(V9_V6_V3,3)\ +PHASE(14) V(V7_V4_V1,4)\ +PHASE(15) V(V8_V5_V2,4)\ +PHASE(16) V(V9_V6_V3,4)\ +PHASE(17) V(V1,0) V(V7,5)V(V4,6)\ +PHASE(18) V(V8_V5_V2,5)\ +PHASE(19) V(V9_V6_V3,5)\ +PHASE(20) V(V1,1) V(V7,6)V(V4,7)\ +PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\ +PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\ +PHASE(23) V(V7,7) echo_23();\ +PHASE(24) V(V8,7) echo_24();\ +PHASE(25) V(V3b,0) V(V9,7) echo_25();\ +PHASE(26) echo_26();\ +PHASE(27) misc_27(); echo_27();\ +PHASE(28) misc_28(); echo_28();\ +PHASE(29) misc_29(); echo_29();\ +PHASE(30) misc_30();V(V3c,0) echo_30();\ +PHASE(31) V(V4,0) V(V1,2)\ + +#if !SPC_DSP_CUSTOM_RUN + +void SPC_DSP::run( int clocks_remain ) +{ + require( clocks_remain > 0 ); + + int const phase = m.phase; + m.phase = (phase + clocks_remain) & 31; + switch ( phase ) + { + loop: + + #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: + GEN_DSP_TIMING + #undef PHASE + + if ( --clocks_remain ) + goto loop; + } +} + +#endif + + +//// Setup + +void SPC_DSP::init( void* ram_64k ) +{ + m.ram = (uint8_t*) ram_64k; + mute_voices( 0 ); + disable_surround( false ); + set_output( 0, 0 ); + reset(); + + #ifndef NDEBUG + // be sure this sign-extends + assert( (int16_t) 0x8000 == -0x8000 ); + + // be sure right shift preserves sign + assert( (-1 >> 1) == -1 ); + + // check clamp macro + int i; + i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); + i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); + + blargg_verify_byte_order(); + #endif +} + +void SPC_DSP::soft_reset_common() +{ + require( m.ram ); // init() must have been called already + + m.noise = 0x4000; + m.echo_hist_pos = m.echo_hist; + m.every_other_sample = 1; + m.echo_offset = 0; + m.phase = 0; + + init_counter(); +} + +void SPC_DSP::soft_reset() +{ + REG(flg) = 0xE0; + soft_reset_common(); +} + +void SPC_DSP::load( uint8_t const regs [register_count] ) +{ + memcpy( m.regs, regs, sizeof m.regs ); + memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); + + // Internal state + for ( int i = voice_count; --i >= 0; ) + { + voice_t* v = &m.voices [i]; + v->brr_offset = 1; + v->vbit = 1 << i; + v->regs = &m.regs [i * 0x10]; + } + m.new_kon = REG(kon); + m.t_dir = REG(dir); + m.t_esa = REG(esa); + + soft_reset_common(); +} + +void SPC_DSP::reset() { load( initial_regs ); } + + +//// State save/load + +#if !SPC_NO_COPY_STATE_FUNCS + +void SPC_State_Copier::copy( void* state, size_t size ) +{ + func( buf, state, size ); +} + +int SPC_State_Copier::copy_int( int state, int size ) +{ + BOOST::uint8_t s [2]; + SET_LE16( s, state ); + func( buf, &s, size ); + return GET_LE16( s ); +} + +void SPC_State_Copier::skip( int count ) +{ + if ( count > 0 ) + { + char temp [64]; + memset( temp, 0, sizeof temp ); + do + { + int n = sizeof temp; + if ( n > count ) + n = count; + count -= n; + func( buf, temp, n ); + } + while ( count ); + } +} + +void SPC_State_Copier::extra() +{ + int n = 0; + SPC_State_Copier& copier = *this; + SPC_COPY( uint8_t, n ); + skip( n ); +} + +void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) +{ + SPC_State_Copier copier( io, copy ); + + // DSP registers + copier.copy( m.regs, register_count ); + + // Internal state + + // Voices + int i; + for ( i = 0; i < voice_count; i++ ) + { + voice_t* v = &m.voices [i]; + + // BRR buffer + int i; + for ( i = 0; i < brr_buf_size; i++ ) + { + int s = v->buf [i]; + SPC_COPY( int16_t, s ); + v->buf [i] = v->buf [i + brr_buf_size] = s; + } + + SPC_COPY( uint16_t, v->interp_pos ); + SPC_COPY( uint16_t, v->brr_addr ); + SPC_COPY( uint16_t, v->env ); + SPC_COPY( int16_t, v->hidden_env ); + SPC_COPY( uint8_t, v->buf_pos ); + SPC_COPY( uint8_t, v->brr_offset ); + SPC_COPY( uint8_t, v->kon_delay ); + { + int m = v->env_mode; + SPC_COPY( uint8_t, m ); + v->env_mode = (enum env_mode_t) m; + } + SPC_COPY( uint8_t, v->t_envx_out ); + + copier.extra(); + } + + // Echo history + for ( i = 0; i < echo_hist_size; i++ ) + { + int j; + for ( j = 0; j < 2; j++ ) + { + int s = m.echo_hist_pos [i] [j]; + SPC_COPY( int16_t, s ); + m.echo_hist [i] [j] = s; // write back at offset 0 + } + } + m.echo_hist_pos = m.echo_hist; + memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); + + // Misc + SPC_COPY( uint8_t, m.every_other_sample ); + SPC_COPY( uint8_t, m.kon ); + + SPC_COPY( uint16_t, m.noise ); + SPC_COPY( uint16_t, m.counter ); + SPC_COPY( uint16_t, m.echo_offset ); + SPC_COPY( uint16_t, m.echo_length ); + SPC_COPY( uint8_t, m.phase ); + + SPC_COPY( uint8_t, m.new_kon ); + SPC_COPY( uint8_t, m.endx_buf ); + SPC_COPY( uint8_t, m.envx_buf ); + SPC_COPY( uint8_t, m.outx_buf ); + + SPC_COPY( uint8_t, m.t_pmon ); + SPC_COPY( uint8_t, m.t_non ); + SPC_COPY( uint8_t, m.t_eon ); + SPC_COPY( uint8_t, m.t_dir ); + SPC_COPY( uint8_t, m.t_koff ); + + SPC_COPY( uint16_t, m.t_brr_next_addr ); + SPC_COPY( uint8_t, m.t_adsr0 ); + SPC_COPY( uint8_t, m.t_brr_header ); + SPC_COPY( uint8_t, m.t_brr_byte ); + SPC_COPY( uint8_t, m.t_srcn ); + SPC_COPY( uint8_t, m.t_esa ); + SPC_COPY( uint8_t, m.t_echo_enabled ); + + SPC_COPY( int16_t, m.t_main_out [0] ); + SPC_COPY( int16_t, m.t_main_out [1] ); + SPC_COPY( int16_t, m.t_echo_out [0] ); + SPC_COPY( int16_t, m.t_echo_out [1] ); + SPC_COPY( int16_t, m.t_echo_in [0] ); + SPC_COPY( int16_t, m.t_echo_in [1] ); + + SPC_COPY( uint16_t, m.t_dir_addr ); + SPC_COPY( uint16_t, m.t_pitch ); + SPC_COPY( int16_t, m.t_output ); + SPC_COPY( uint16_t, m.t_echo_ptr ); + SPC_COPY( uint8_t, m.t_looped ); + + copier.extra(); +} +#endif diff --git a/snes/alt/dsp/SPC_DSP.h b/snes/alt/dsp/SPC_DSP.h new file mode 100755 index 00000000..4522ace9 --- /dev/null +++ b/snes/alt/dsp/SPC_DSP.h @@ -0,0 +1,304 @@ +// Highly accurate SNES SPC-700 DSP emulator + +// snes_spc 0.9.0 +#ifndef SPC_DSP_H +#define SPC_DSP_H + +#include "blargg_common.h" + +extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } + +class SPC_DSP { +public: + typedef BOOST::uint8_t uint8_t; + +// Setup + + // Initializes DSP and has it use the 64K RAM provided + void init( void* ram_64k ); + + // Sets destination for output samples. If out is NULL or out_size is 0, + // doesn't generate any. + typedef short sample_t; + void set_output( sample_t* out, int out_size ); + + // Number of samples written to output since it was last set, always + // a multiple of 2. Undefined if more samples were generated than + // output buffer could hold. + int sample_count() const; + +// Emulation + + // Resets DSP to power-on state + void reset(); + + // Emulates pressing reset switch on SNES + void soft_reset(); + + // Reads/writes DSP registers. For accuracy, you must first call run() + // to catch the DSP up to present. + int read ( int addr ) const; + void write( int addr, int data ); + + // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks + // a pair of samples is be generated. + void run( int clock_count ); + +// Sound control + + // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). + // Reduces emulation accuracy. + enum { voice_count = 8 }; + void mute_voices( int mask ); + +// State + + // Resets DSP and uses supplied values to initialize registers + enum { register_count = 128 }; + void load( uint8_t const regs [register_count] ); + + // Saves/loads exact emulator state + enum { state_size = 640 }; // maximum space needed when saving + typedef dsp_copy_func_t copy_func_t; + void copy_state( unsigned char** io, copy_func_t ); + + // Returns non-zero if new key-on events occurred since last call + bool check_kon(); + +// DSP register addresses + + // Global registers + enum { + r_mvoll = 0x0C, r_mvolr = 0x1C, + r_evoll = 0x2C, r_evolr = 0x3C, + r_kon = 0x4C, r_koff = 0x5C, + r_flg = 0x6C, r_endx = 0x7C, + r_efb = 0x0D, r_pmon = 0x2D, + r_non = 0x3D, r_eon = 0x4D, + r_dir = 0x5D, r_esa = 0x6D, + r_edl = 0x7D, + r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F + }; + + // Voice registers + enum { + v_voll = 0x00, v_volr = 0x01, + v_pitchl = 0x02, v_pitchh = 0x03, + v_srcn = 0x04, v_adsr0 = 0x05, + v_adsr1 = 0x06, v_gain = 0x07, + v_envx = 0x08, v_outx = 0x09 + }; + +public: + enum { extra_size = 16 }; + sample_t* extra() { return m.extra; } + sample_t const* out_pos() const { return m.out; } + void disable_surround( bool ) { } // not supported +public: + BLARGG_DISABLE_NOTHROW + + typedef BOOST::int8_t int8_t; + typedef BOOST::int16_t int16_t; + + enum { echo_hist_size = 8 }; + + enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; + enum { brr_buf_size = 12 }; + struct voice_t + { + int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) + int buf_pos; // place in buffer where next samples will be decoded + int interp_pos; // relative fractional position in sample (0x1000 = 1.0) + int brr_addr; // address of current BRR block + int brr_offset; // current decoding offset in BRR block + uint8_t* regs; // pointer to voice's DSP registers + int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. + int kon_delay; // KON delay/current setup phase + env_mode_t env_mode; + int env; // current envelope level + int hidden_env; // used by GAIN mode 7, very obscure quirk + uint8_t t_envx_out; + }; +private: + enum { brr_block_size = 9 }; + + struct state_t + { + uint8_t regs [register_count]; + + // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) + int echo_hist [echo_hist_size * 2] [2]; + int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] + + int every_other_sample; // toggles every sample + int kon; // KON value when last checked + int noise; + int counter; + int echo_offset; // offset from ESA in echo buffer + int echo_length; // number of bytes that echo_offset will stop at + int phase; // next clock cycle to run (0-31) + bool kon_check; // set when a new KON occurs + + // Hidden registers also written to when main register is written to + int new_kon; + uint8_t endx_buf; + uint8_t envx_buf; + uint8_t outx_buf; + + // Temporary state between clocks + + // read once per sample + int t_pmon; + int t_non; + int t_eon; + int t_dir; + int t_koff; + + // read a few clocks ahead then used + int t_brr_next_addr; + int t_adsr0; + int t_brr_header; + int t_brr_byte; + int t_srcn; + int t_esa; + int t_echo_enabled; + + // internal state that is recalculated every sample + int t_dir_addr; + int t_pitch; + int t_output; + int t_looped; + int t_echo_ptr; + + // left/right sums + int t_main_out [2]; + int t_echo_out [2]; + int t_echo_in [2]; + + voice_t voices [voice_count]; + + // non-emulation state + uint8_t* ram; // 64K shared RAM between DSP and SMP + int mute_mask; + sample_t* out; + sample_t* out_end; + sample_t* out_begin; + sample_t extra [extra_size]; + }; + state_t m; + + void init_counter(); + void run_counters(); + unsigned read_counter( int rate ); + + int interpolate( voice_t const* v ); + void run_envelope( voice_t* const v ); + void decode_brr( voice_t* v ); + + void misc_27(); + void misc_28(); + void misc_29(); + void misc_30(); + + void voice_output( voice_t const* v, int ch ); + void voice_V1( voice_t* const ); + void voice_V2( voice_t* const ); + void voice_V3( voice_t* const ); + void voice_V3a( voice_t* const ); + void voice_V3b( voice_t* const ); + void voice_V3c( voice_t* const ); + void voice_V4( voice_t* const ); + void voice_V5( voice_t* const ); + void voice_V6( voice_t* const ); + void voice_V7( voice_t* const ); + void voice_V8( voice_t* const ); + void voice_V9( voice_t* const ); + void voice_V7_V4_V1( voice_t* const ); + void voice_V8_V5_V2( voice_t* const ); + void voice_V9_V6_V3( voice_t* const ); + + void echo_read( int ch ); + int echo_output( int ch ); + void echo_write( int ch ); + void echo_22(); + void echo_23(); + void echo_24(); + void echo_25(); + void echo_26(); + void echo_27(); + void echo_28(); + void echo_29(); + void echo_30(); + + void soft_reset_common(); +}; + +#include + +inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } + +inline int SPC_DSP::read( int addr ) const +{ + assert( (unsigned) addr < register_count ); + return m.regs [addr]; +} + +inline void SPC_DSP::write( int addr, int data ) +{ + assert( (unsigned) addr < register_count ); + + m.regs [addr] = (uint8_t) data; + switch ( addr & 0x0F ) + { + case v_envx: + m.envx_buf = (uint8_t) data; + break; + + case v_outx: + m.outx_buf = (uint8_t) data; + break; + + case 0x0C: + if ( addr == r_kon ) + m.new_kon = (uint8_t) data; + + if ( addr == r_endx ) // always cleared, regardless of data written + { + m.endx_buf = 0; + m.regs [r_endx] = 0; + } + break; + } +} + +inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } + +inline bool SPC_DSP::check_kon() +{ + bool old = m.kon_check; + m.kon_check = 0; + return old; +} + +#if !SPC_NO_COPY_STATE_FUNCS + +class SPC_State_Copier { + SPC_DSP::copy_func_t func; + unsigned char** buf; +public: + SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } + void copy( void* state, size_t size ); + int copy_int( int state, int size ); + void skip( int count ); + void extra(); +}; + +#define SPC_COPY( type, state )\ +{\ + state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\ + assert( (BOOST::type) state == state );\ +} + +#endif + +#endif diff --git a/snes/alt/dsp/blargg_common.h b/snes/alt/dsp/blargg_common.h new file mode 100755 index 00000000..75edff39 --- /dev/null +++ b/snes/alt/dsp/blargg_common.h @@ -0,0 +1,186 @@ +// Sets up common environment for Shay Green's libraries. +// To change configuration options, modify blargg_config.h, not this file. + +// snes_spc 0.9.0 +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +#include +#include +#include +#include + +#undef BLARGG_COMMON_H +// allow blargg_config.h to #include blargg_common.h +#include "blargg_config.h" +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +// BLARGG_RESTRICT: equivalent to restrict, where supported +#if defined (__GNUC__) || _MSC_VER >= 1100 + #define BLARGG_RESTRICT __restrict +#else + #define BLARGG_RESTRICT +#endif + +// STATIC_CAST(T,expr): Used in place of static_cast (expr) +#ifndef STATIC_CAST + #define STATIC_CAST(T,expr) ((T) (expr)) +#endif + +// blargg_err_t (0 on success, otherwise error string) +#ifndef blargg_err_t + typedef const char* blargg_err_t; +#endif + +// blargg_vector - very lightweight vector of POD types (no constructor/destructor) +template +class blargg_vector { + T* begin_; + size_t size_; +public: + blargg_vector() : begin_( 0 ), size_( 0 ) { } + ~blargg_vector() { free( begin_ ); } + size_t size() const { return size_; } + T* begin() const { return begin_; } + T* end() const { return begin_ + size_; } + blargg_err_t resize( size_t n ) + { + // TODO: blargg_common.cpp to hold this as an outline function, ugh + void* p = realloc( begin_, n * sizeof (T) ); + if ( p ) + begin_ = (T*) p; + else if ( n > size_ ) // realloc failure only a problem if expanding + return "Out of memory"; + size_ = n; + return 0; + } + void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } + T& operator [] ( size_t n ) const + { + assert( n <= size_ ); // <= to allow past-the-end value + return begin_ [n]; + } +}; + +#ifndef BLARGG_DISABLE_NOTHROW + // throw spec mandatory in ISO C++ if operator new can return NULL + #if __cplusplus >= 199711 || defined (__GNUC__) + #define BLARGG_THROWS( spec ) throw spec + #else + #define BLARGG_THROWS( spec ) + #endif + #define BLARGG_DISABLE_NOTHROW \ + void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ + void operator delete ( void* p ) { free( p ); } + #define BLARGG_NEW new +#else + #include + #define BLARGG_NEW new (std::nothrow) +#endif + +// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) +#define BLARGG_4CHAR( a, b, c, d ) \ + ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) + +// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. +#ifndef BOOST_STATIC_ASSERT + #ifdef _MSC_VER + // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) + #else + // Some other compilers fail when declaring same function multiple times in class, + // so differentiate them by line + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) + #endif +#endif + +// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, +// compiler is assumed to support bool. If undefined, availability is determined. +#ifndef BLARGG_COMPILER_HAS_BOOL + #if defined (__MWERKS__) + #if !__option(bool) + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (_MSC_VER) + #if _MSC_VER < 1100 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (__GNUC__) + // supports bool + #elif __cplusplus < 199711 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif +#endif +#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL + // If you get errors here, modify your blargg_config.h file + typedef int bool; + const bool true = 1; + const bool false = 0; +#endif + +// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough + +#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF + typedef long blargg_long; +#else + typedef int blargg_long; +#endif + +#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF + typedef unsigned long blargg_ulong; +#else + typedef unsigned blargg_ulong; +#endif + +// BOOST::int8_t etc. + +// HAVE_STDINT_H: If defined, use for int8_t etc. +#if defined (HAVE_STDINT_H) + #include + #define BOOST + +// HAVE_INTTYPES_H: If defined, use for int8_t etc. +#elif defined (HAVE_INTTYPES_H) + #include + #define BOOST + +#else + struct BOOST + { + #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F + typedef signed char int8_t; + typedef unsigned char uint8_t; + #else + // No suitable 8-bit type available + typedef struct see_blargg_common_h int8_t; + typedef struct see_blargg_common_h uint8_t; + #endif + + #if USHRT_MAX == 0xFFFF + typedef short int16_t; + typedef unsigned short uint16_t; + #else + // No suitable 16-bit type available + typedef struct see_blargg_common_h int16_t; + typedef struct see_blargg_common_h uint16_t; + #endif + + #if ULONG_MAX == 0xFFFFFFFF + typedef long int32_t; + typedef unsigned long uint32_t; + #elif UINT_MAX == 0xFFFFFFFF + typedef int int32_t; + typedef unsigned int uint32_t; + #else + // No suitable 32-bit type available + typedef struct see_blargg_common_h int32_t; + typedef struct see_blargg_common_h uint32_t; + #endif + }; +#endif + +#endif +#endif diff --git a/snes/alt/dsp/blargg_config.h b/snes/alt/dsp/blargg_config.h new file mode 100755 index 00000000..d85d2663 --- /dev/null +++ b/snes/alt/dsp/blargg_config.h @@ -0,0 +1,24 @@ +// snes_spc 0.9.0 user configuration file. Don't replace when updating library. + +// snes_spc 0.9.0 +#ifndef BLARGG_CONFIG_H +#define BLARGG_CONFIG_H + +// Uncomment to disable debugging checks +#define NDEBUG 1 + +// Uncomment to enable platform-specific (and possibly non-portable) optimizations +//#define BLARGG_NONPORTABLE 1 + +// Uncomment if automatic byte-order determination doesn't work +//#define BLARGG_BIG_ENDIAN 1 + +// Uncomment if you get errors in the bool section of blargg_common.h +//#define BLARGG_COMPILER_HAS_BOOL 1 + +// Use standard config.h if present +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#endif diff --git a/snes/alt/dsp/blargg_endian.h b/snes/alt/dsp/blargg_endian.h new file mode 100755 index 00000000..f2daca64 --- /dev/null +++ b/snes/alt/dsp/blargg_endian.h @@ -0,0 +1,185 @@ +// CPU Byte Order Utilities + +// snes_spc 0.9.0 +#ifndef BLARGG_ENDIAN +#define BLARGG_ENDIAN + +#include "blargg_common.h" + +// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) +#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ + defined (__x86_64__) || defined (__ia64__) || defined (__i386__) + #define BLARGG_CPU_X86 1 + #define BLARGG_CPU_CISC 1 +#endif + +#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) + #define BLARGG_CPU_POWERPC 1 + #define BLARGG_CPU_RISC 1 +#endif + +// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only +// one may be #defined to 1. Only needed if something actually depends on byte order. +#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) +#ifdef __GLIBC__ + // GCC handles this for us + #include + #if __BYTE_ORDER == __LITTLE_ENDIAN + #define BLARGG_LITTLE_ENDIAN 1 + #elif __BYTE_ORDER == __BIG_ENDIAN + #define BLARGG_BIG_ENDIAN 1 + #endif +#else + +#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ + (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) + #define BLARGG_LITTLE_ENDIAN 1 +#endif + +#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ + defined (__sparc__) || BLARGG_CPU_POWERPC || \ + (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) + #define BLARGG_BIG_ENDIAN 1 +#elif !defined (__mips__) + // No endian specified; assume little-endian, since it's most common + #define BLARGG_LITTLE_ENDIAN 1 +#endif +#endif +#endif + +#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN + #undef BLARGG_LITTLE_ENDIAN + #undef BLARGG_BIG_ENDIAN +#endif + +inline void blargg_verify_byte_order() +{ + #ifndef NDEBUG + #if BLARGG_BIG_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i == 0 ); + #elif BLARGG_LITTLE_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i != 0 ); + #endif + #endif +} + +inline unsigned get_le16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 8 | + (unsigned) ((unsigned char const*) p) [1]; +} + +inline blargg_ulong get_le32( void const* p ) +{ + return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | + (blargg_ulong) ((unsigned char const*) p) [2] << 16 | + (blargg_ulong) ((unsigned char const*) p) [1] << 8 | + (blargg_ulong) ((unsigned char const*) p) [0]; +} + +inline blargg_ulong get_be32( void const* p ) +{ + return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | + (blargg_ulong) ((unsigned char const*) p) [1] << 16 | + (blargg_ulong) ((unsigned char const*) p) [2] << 8 | + (blargg_ulong) ((unsigned char const*) p) [3]; +} + +inline void set_le16( void* p, unsigned n ) +{ + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [0] = (unsigned char) n; +} + +inline void set_be16( void* p, unsigned n ) +{ + ((unsigned char*) p) [0] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) n; +} + +inline void set_le32( void* p, blargg_ulong n ) +{ + ((unsigned char*) p) [0] = (unsigned char) n; + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [2] = (unsigned char) (n >> 16); + ((unsigned char*) p) [3] = (unsigned char) (n >> 24); +} + +inline void set_be32( void* p, blargg_ulong n ) +{ + ((unsigned char*) p) [3] = (unsigned char) n; + ((unsigned char*) p) [2] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) (n >> 16); + ((unsigned char*) p) [0] = (unsigned char) (n >> 24); +} + +#if BLARGG_NONPORTABLE + // Optimized implementation if byte order is known + #if BLARGG_LITTLE_ENDIAN + #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) + #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) + #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + #elif BLARGG_BIG_ENDIAN + #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) + #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) + #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + + #if BLARGG_CPU_POWERPC + // PowerPC has special byte-reversed instructions + #if defined (__MWERKS__) + #define GET_LE16( addr ) (__lhbrx( addr, 0 )) + #define GET_LE32( addr ) (__lwbrx( addr, 0 )) + #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) + #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) + #elif defined (__GNUC__) + #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) + #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) + #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) + #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) + #endif + #endif + #endif +#endif + +#ifndef GET_LE16 + #define GET_LE16( addr ) get_le16( addr ) + #define SET_LE16( addr, data ) set_le16( addr, data ) +#endif + +#ifndef GET_LE32 + #define GET_LE32( addr ) get_le32( addr ) + #define SET_LE32( addr, data ) set_le32( addr, data ) +#endif + +#ifndef GET_BE16 + #define GET_BE16( addr ) get_be16( addr ) + #define SET_BE16( addr, data ) set_be16( addr, data ) +#endif + +#ifndef GET_BE32 + #define GET_BE32( addr ) get_be32( addr ) + #define SET_BE32( addr, data ) set_be32( addr, data ) +#endif + +// auto-selecting versions + +inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } +inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } +inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } +inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } +inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } +inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } +inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } +inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } + +#endif diff --git a/snes/alt/dsp/blargg_source.h b/snes/alt/dsp/blargg_source.h new file mode 100755 index 00000000..5e45c4fb --- /dev/null +++ b/snes/alt/dsp/blargg_source.h @@ -0,0 +1,100 @@ +/* Included at the beginning of library source files, after all other #include lines. +Sets up helpful macros and services used in my source code. They don't need +module an annoying module prefix on their names since they are defined after +all other #include lines. */ + +// snes_spc 0.9.0 +#ifndef BLARGG_SOURCE_H +#define BLARGG_SOURCE_H + +// If debugging is enabled, abort program if expr is false. Meant for checking +// internal state and consistency. A failed assertion indicates a bug in the module. +// void assert( bool expr ); +#include + +// If debugging is enabled and expr is false, abort program. Meant for checking +// caller-supplied parameters and operations that are outside the control of the +// module. A failed requirement indicates a bug outside the module. +// void require( bool expr ); +#undef require +#define require( expr ) assert( expr ) + +// Like printf() except output goes to debug log file. Might be defined to do +// nothing (not even evaluate its arguments). +// void dprintf( const char* format, ... ); +static inline void blargg_dprintf_( const char*, ... ) { } +#undef dprintf +#define dprintf (1) ? (void) 0 : blargg_dprintf_ + +// If enabled, evaluate expr and if false, make debug log entry with source file +// and line. Meant for finding situations that should be examined further, but that +// don't indicate a problem. In all cases, execution continues normally. +#undef check +#define check( expr ) ((void) 0) + +// If expr yields error string, return it from current function, otherwise continue. +#undef RETURN_ERR +#define RETURN_ERR( expr ) do { \ + blargg_err_t blargg_return_err_ = (expr); \ + if ( blargg_return_err_ ) return blargg_return_err_; \ + } while ( 0 ) + +// If ptr is 0, return out of memory error string. +#undef CHECK_ALLOC +#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) + +// Avoid any macros which evaluate their arguments multiple times +#undef min +#undef max + +#define DEF_MIN_MAX( type ) \ + static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ + static inline type max( type x, type y ) { if ( y < x ) return x; return y; } + +DEF_MIN_MAX( int ) +DEF_MIN_MAX( unsigned ) +DEF_MIN_MAX( long ) +DEF_MIN_MAX( unsigned long ) +DEF_MIN_MAX( float ) +DEF_MIN_MAX( double ) + +#undef DEF_MIN_MAX + +/* +// using const references generates crappy code, and I am currenly only using these +// for built-in types, so they take arguments by value + +// TODO: remove +inline int min( int x, int y ) +template +inline T min( T x, T y ) +{ + if ( x < y ) + return x; + return y; +} + +template +inline T max( T x, T y ) +{ + if ( x < y ) + return y; + return x; +} +*/ + +// TODO: good idea? bad idea? +#undef byte +#define byte byte_ +typedef unsigned char byte; + +// deprecated +#define BLARGG_CHECK_ALLOC CHECK_ALLOC +#define BLARGG_RETURN_ERR RETURN_ERR + +// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check +#ifdef BLARGG_SOURCE_BEGIN + #include BLARGG_SOURCE_BEGIN +#endif + +#endif diff --git a/snes/alt/dsp/dsp.cpp b/snes/alt/dsp/dsp.cpp new file mode 100755 index 00000000..d0c9e077 --- /dev/null +++ b/snes/alt/dsp/dsp.cpp @@ -0,0 +1,66 @@ +#include + +#define DSP_CPP +namespace SNES { + +DSP dsp; + +#include "serialization.cpp" +#include "SPC_DSP.cpp" + +void DSP::step(unsigned clocks) { + clock += clocks; +} + +void DSP::synchronize_smp() { + if(SMP::Threaded == true) { + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(smp.thread); + } else { + while(clock >= 0) smp.enter(); + } +} + +void DSP::enter() { + spc_dsp.run(1); + step(24); + + signed count = spc_dsp.sample_count(); + if(count > 0) { + for(unsigned n = 0; n < count; n += 2) audio.sample(samplebuffer[n + 0], samplebuffer[n + 1]); + spc_dsp.set_output(samplebuffer, 8192); + } +} + +uint8 DSP::read(uint8 addr) { + return spc_dsp.read(addr); +} + +void DSP::write(uint8 addr, uint8 data) { + spc_dsp.write(addr, data); +} + +void DSP::power() { + spc_dsp.init(smp.apuram); + spc_dsp.reset(); + spc_dsp.set_output(samplebuffer, 8192); +} + +void DSP::reset() { + spc_dsp.soft_reset(); + spc_dsp.set_output(samplebuffer, 8192); +} + +void DSP::channel_enable(unsigned channel, bool enable) { + channel_enabled[channel & 7] = enable; + unsigned mask = 0; + for(unsigned i = 0; i < 8; i++) { + if(channel_enabled[i] == false) mask |= 1 << i; + } + spc_dsp.mute_voices(mask); +} + +DSP::DSP() { + for(unsigned i = 0; i < 8; i++) channel_enabled[i] = true; +} + +} diff --git a/snes/alt/dsp/dsp.hpp b/snes/alt/dsp/dsp.hpp new file mode 100755 index 00000000..29cab585 --- /dev/null +++ b/snes/alt/dsp/dsp.hpp @@ -0,0 +1,28 @@ +#include "SPC_DSP.h" + +class DSP : public Processor, public ChipDebugger { +public: + enum : bool { Threaded = false }; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_smp(); + + uint8 read(uint8 addr); + void write(uint8 addr, uint8 data); + + void enter(); + void power(); + void reset(); + + void channel_enable(unsigned channel, bool enable); + + void serialize(serializer&); + bool property(unsigned id, string &name, string &value) { return false; } + DSP(); + +private: + SPC_DSP spc_dsp; + int16 samplebuffer[8192]; + bool channel_enabled[8]; +}; + +extern DSP dsp; diff --git a/snes/alt/dsp/serialization.cpp b/snes/alt/dsp/serialization.cpp new file mode 100755 index 00000000..0565a1b5 --- /dev/null +++ b/snes/alt/dsp/serialization.cpp @@ -0,0 +1,31 @@ +#ifdef DSP_CPP + +static void dsp_state_save(unsigned char **out, void *in, size_t size) { + memcpy(*out, in, size); + *out += size; +} + +static void dsp_state_load(unsigned char **in, void *out, size_t size) { + memcpy(out, *in, size); + *in += size; +} + +void DSP::serialize(serializer &s) { + Processor::serialize(s); + s.array(samplebuffer); + + unsigned char state[SPC_DSP::state_size]; + unsigned char *p = state; + memset(&state, 0, SPC_DSP::state_size); + if(s.mode() == serializer::Save) { + spc_dsp.copy_state(&p, dsp_state_save); + s.array(state); + } else if(s.mode() == serializer::Load) { + s.array(state); + spc_dsp.copy_state(&p, dsp_state_load); + } else { + s.array(state); + } +} + +#endif diff --git a/snes/alt/ppu-compatibility/debugger/debugger.cpp b/snes/alt/ppu-compatibility/debugger/debugger.cpp new file mode 100755 index 00000000..2a294c5d --- /dev/null +++ b/snes/alt/ppu-compatibility/debugger/debugger.cpp @@ -0,0 +1,349 @@ +#ifdef PPU_CPP + +uint8 PPUDebugger::vram_mmio_read(uint16 addr) { + uint8 data = PPU::vram_mmio_read(addr); + debugger.breakpoint_test(Debugger::Breakpoint::Source::VRAM, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void PPUDebugger::vram_mmio_write(uint16 addr, uint8 data) { + PPU::vram_mmio_write(addr, data); + debugger.breakpoint_test(Debugger::Breakpoint::Source::VRAM, Debugger::Breakpoint::Mode::Write, addr, data); +} + +uint8 PPUDebugger::oam_mmio_read(uint16 addr) { + uint8 data = PPU::oam_mmio_read(addr); + debugger.breakpoint_test(Debugger::Breakpoint::Source::OAM, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void PPUDebugger::oam_mmio_write(uint16 addr, uint8 data) { + PPU::oam_mmio_write(addr, data); + debugger.breakpoint_test(Debugger::Breakpoint::Source::OAM, Debugger::Breakpoint::Mode::Write, addr, data); +} + +uint8 PPUDebugger::cgram_mmio_read(uint16 addr) { + uint8 data = PPU::cgram_mmio_read(addr); + debugger.breakpoint_test(Debugger::Breakpoint::Source::CGRAM, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void PPUDebugger::cgram_mmio_write(uint16 addr, uint8 data) { + PPU::cgram_mmio_write(addr, data); + debugger.breakpoint_test(Debugger::Breakpoint::Source::CGRAM, Debugger::Breakpoint::Mode::Write, addr, data); +} + +PPUDebugger::PPUDebugger() { +} + +bool PPUDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //internal + item("S-PPU1 MDR", string("0x", hex<2>(regs.ppu1_mdr))); + item("S-PPU2 MDR", string("0x", hex<2>(regs.ppu2_mdr))); + + //$2100 + item("$2100", ""); + item("Display Disable", regs.display_disabled); + item("Display Brightness", (unsigned)regs.display_brightness); + + //$2101 + item("$2101", ""); + item("OAM Base Size", (unsigned)regs.oam_basesize); + item("OAM Name Select", (unsigned)regs.oam_nameselect); + item("OAM Name Base Address", string("0x", hex<4>(regs.oam_tdaddr))); + + //$2102-$2103 + item("$2102-$2103", ""); + item("OAM Base Address", string("0x", hex<4>(regs.oam_baseaddr))); + item("OAM Priority", regs.oam_priority); + + //$2105 + item("$2105", ""); + item("BG1 Tile Size", regs.bg_tilesize[BG1] ? "16x16" : "8x8"); + item("BG2 Tile Size", regs.bg_tilesize[BG2] ? "16x16" : "8x8"); + item("BG3 Tile Size", regs.bg_tilesize[BG3] ? "16x16" : "8x8"); + item("BG4 Tile Size", regs.bg_tilesize[BG4] ? "16x16" : "8x8"); + item("BG3 Priority", regs.bg3_priority); + item("BG Mode", (unsigned)regs.bg_mode); + + //$2106 + item("$2106", ""); + item("Mosaic Size", (unsigned)regs.mosaic_size); + item("BG1 Mosaic Enable", regs.mosaic_enabled[BG1]); + item("BG2 Mosaic Enable", regs.mosaic_enabled[BG2]); + item("BG3 Mosaic Enable", regs.mosaic_enabled[BG3]); + item("BG4 Mosaic Enable", regs.mosaic_enabled[BG4]); + + static char screen_size[4][8] = { "32x32", "32x64", "64x32", "64x64" }; + + //$2107 + item("$2107", ""); + item("BG1 Screen Address", string("0x", hex<4>(regs.bg_scaddr[BG1]))); + item("BG1 Screen Size", screen_size[regs.bg_scsize[BG1]]); + + //$2108 + item("$2108", ""); + item("BG2 Screen Address", string("0x", hex<4>(regs.bg_scaddr[BG2]))); + item("BG2 Screen Size", screen_size[regs.bg_scsize[BG2]]); + + //$2109 + item("$2109", ""); + item("BG3 Screen Address", string("0x", hex<4>(regs.bg_scaddr[BG3]))); + item("BG3 Screen Size", screen_size[regs.bg_scsize[BG3]]); + + //$210a + item("$210a", ""); + item("BG4 Screen Address", string("0x", hex<4>(regs.bg_scaddr[BG4]))); + item("BG4 Screen Size", screen_size[regs.bg_scsize[BG4]]); + + //$210b + item("$210b", ""); + item("BG1 Name Base Address", string("0x", hex<4>(regs.bg_tdaddr[BG1]))); + item("BG2 Name Base Address", string("0x", hex<4>(regs.bg_tdaddr[BG2]))); + + //$210c + item("$210c", ""); + item("BG3 Name Base Address", string("0x", hex<4>(regs.bg_tdaddr[BG3]))); + item("BG4 Name Base Address", string("0x", hex<4>(regs.bg_tdaddr[BG4]))); + + //$210d + item("$210d", ""); + item("Mode 7 Scroll H-offset", (unsigned)(regs.m7_hofs & 0x1fff)); + item("BG1 Scroll H-offset", (unsigned)(regs.bg_hofs[BG1] & 0x03ff)); + + //$210e + item("$210e", ""); + item("Mode 7 Scroll V-offset", (unsigned)(regs.m7_vofs & 0x1fff)); + item("BG1 Scroll V-offset", (unsigned)(regs.bg_vofs[BG1] & 0x03ff)); + + //$210f + item("$210f", ""); + item("BG2 Scroll H-offset", (unsigned)(regs.bg_hofs[BG2] & 0x03ff)); + + //$2110 + item("$2110", ""); + item("BG2 Scroll V-offset", (unsigned)(regs.bg_vofs[BG2] & 0x03ff)); + + //$2111 + item("$2111", ""); + item("BG3 Scroll H-offset", (unsigned)(regs.bg_hofs[BG3] & 0x03ff)); + + //$2112 + item("$2112", ""); + item("BG3 Scroll V-offset", (unsigned)(regs.bg_vofs[BG3] & 0x03ff)); + + //$2113 + item("$2113", ""); + item("BG4 Scroll H-offset", (unsigned)(regs.bg_hofs[BG4] & 0x03ff)); + + //$2114 + item("$2114", ""); + item("BG4 Scroll V-offset", (unsigned)(regs.bg_vofs[BG4] & 0x03ff)); + + //$2115 + item("$2115", ""); + item("VRAM Increment Mode", (unsigned)regs.vram_incmode); + item("VRAM Increment Formation", (unsigned)regs.vram_mapping); + item("VRAM Increment Size", (unsigned)regs.vram_incsize); + + //$2116-$2117 + item("$2116-$2117", ""); + item("VRAM Address", string("0x", hex<4>(regs.vram_addr))); + + //$211a + item("$211a", ""); + item("Mode 7 Repeat", (unsigned)regs.mode7_repeat); + item("Mode 7 V-flip", regs.mode7_vflip); + item("Mode 7 H-flip", regs.mode7_hflip); + + //$211b + item("$211b", ""); + item("Mode 7 A", (unsigned)regs.m7a); + + //$211c + item("$211c", ""); + item("Mode 7 B", (unsigned)regs.m7b); + + //$211d + item("$211d", ""); + item("Mode 7 C", (unsigned)regs.m7c); + + //$211e + item("$211e", ""); + item("Mode 7 D", (unsigned)regs.m7d); + + //$211f + item("$211f", ""); + item("Mode 7 X", (unsigned)regs.m7x); + + //$2120 + item("$2120", ""); + item("Mode 7 Y", (unsigned)regs.m7y); + + //$2121 + item("$2121", ""); + item("CGRAM Address", string("0x", hex<4>(regs.cgram_addr))); + + //$2123 + item("$2123", ""); + item("BG1 Window 1 Enable", regs.window1_enabled[BG1]); + item("BG1 Window 1 Invert", regs.window1_invert [BG1]); + item("BG1 Window 2 Enable", regs.window2_enabled[BG1]); + item("BG1 Window 2 Invert", regs.window2_invert [BG1]); + item("BG2 Window 1 Enable", regs.window1_enabled[BG2]); + item("BG2 Window 1 Invert", regs.window1_invert [BG2]); + item("BG2 Window 2 Enable", regs.window2_enabled[BG2]); + item("BG2 Window 2 Invert", regs.window2_invert [BG2]); + + //$2124 + item("$2124", ""); + item("BG3 Window 1 Enable", regs.window1_enabled[BG3]); + item("BG3 Window 1 Invert", regs.window1_invert [BG3]); + item("BG3 Window 2 Enable", regs.window2_enabled[BG3]); + item("BG3 Window 2 Invert", regs.window2_invert [BG3]); + item("BG4 Window 1 Enable", regs.window1_enabled[BG4]); + item("BG4 Window 1 Invert", regs.window1_invert [BG4]); + item("BG4 Window 2 Enable", regs.window2_enabled[BG4]); + item("BG4 Window 2 Invert", regs.window2_invert [BG4]); + + //$2125 + item("$2125", ""); + item("OAM Window 1 Enable", regs.window1_enabled[OAM]); + item("OAM Window 1 Invert", regs.window1_invert [OAM]); + item("OAM Window 2 Enable", regs.window2_enabled[OAM]); + item("OAM Window 2 Invert", regs.window2_invert [OAM]); + item("Color Window 1 Enable", regs.window1_enabled[COL]); + item("Color Window 1 Invert", regs.window1_invert [COL]); + item("Color Window 2 Enable", regs.window2_enabled[COL]); + item("Color Window 2 Invert", regs.window2_enabled[COL]); + + //$2126 + item("$2126", ""); + item("Window 1 Left", (unsigned)regs.window1_left); + + //$2127 + item("$2127", ""); + item("Window 1 Right", (unsigned)regs.window1_right); + + //$2128 + item("$2128", ""); + item("Window 2 Left", (unsigned)regs.window2_left); + + //$2129 + item("$2129", ""); + item("Window 2 Right", (unsigned)regs.window2_right); + + static char window_mask_mode[4][8] = { "OR", "AND", "XOR", "XNOR" }; + + //$212a + item("$212a", ""); + item("BG1 Window Mask", window_mask_mode[regs.window_mask[BG1]]); + item("BG2 Window Mask", window_mask_mode[regs.window_mask[BG2]]); + item("BG3 Window Mask", window_mask_mode[regs.window_mask[BG3]]); + item("BG4 Window Mask", window_mask_mode[regs.window_mask[BG4]]); + + //$212b + item("$212b", ""); + item("OAM Window Mask", window_mask_mode[regs.window_mask[OAM]]); + item("Color Window Mask", window_mask_mode[regs.window_mask[COL]]); + + //$212c + item("$212c", ""); + item("BG1 Mainscreen Enable", regs.bg_enabled[BG1]); + item("BG2 Mainscreen Enable", regs.bg_enabled[BG2]); + item("BG3 Mainscreen Enable", regs.bg_enabled[BG3]); + item("BG4 Mainscreen Enable", regs.bg_enabled[BG4]); + item("OAM Mainscreen Enable", regs.bg_enabled[OAM]); + + //$212d + item("$212d", ""); + item("BG1 Subscreen Enable", regs.bgsub_enabled[BG1]); + item("BG2 Subscreen Enable", regs.bgsub_enabled[BG2]); + item("BG3 Subscreen Enable", regs.bgsub_enabled[BG3]); + item("BG4 Subscreen Enable", regs.bgsub_enabled[BG4]); + item("OAM Subscreen Enable", regs.bgsub_enabled[OAM]); + + //$212e + item("$212e", ""); + item("BG1 Mainscreen Window Enable", regs.window_enabled[BG1]); + item("BG2 Mainscreen Window Enable", regs.window_enabled[BG2]); + item("BG3 Mainscreen Window Enable", regs.window_enabled[BG3]); + item("BG4 Mainscreen Window Enable", regs.window_enabled[BG4]); + item("OAM Mainscreen Window Enable", regs.window_enabled[OAM]); + + //$212f + item("$212f", ""); + item("BG1 Subscreen Window Enable", regs.sub_window_enabled[BG1]); + item("BG2 Subscreen Window Enable", regs.sub_window_enabled[BG2]); + item("BG3 Subscreen Window Enable", regs.sub_window_enabled[BG3]); + item("BG4 Subscreen Window Enable", regs.sub_window_enabled[BG4]); + item("OAM Subscreen Window Enable", regs.sub_window_enabled[OAM]); + + static char color_window_mask_mode[4][32] = { "Always", "Never", "Inside Window Only", "Outside Window Only" }; + + //$2130 + item("$2130", ""); + item("Color Mainscreen Window Mask", color_window_mask_mode[regs.color_mask]); + item("Color Subscreen Window Mask", color_window_mask_mode[regs.colorsub_mask]); + item("Color Add/Subtract Mode", !regs.addsub_mode ? "Fixed Color" : "Subscreen"); + item("Direct Color", regs.direct_color); + + //$2131 + item("$2131", ""); + item("Color Mode", !regs.color_mode ? "Add" : "Subtract"); + item("Color Halve", regs.color_halve); + item("BG1 Color Enable", regs.color_enabled[BG1]); + item("BG2 Color Enable", regs.color_enabled[BG2]); + item("BG3 Color Enable", regs.color_enabled[BG3]); + item("BG4 Color Enable", regs.color_enabled[BG4]); + item("OAM Color Enable", regs.color_enabled[OAM]); + item("Back Color Enable", regs.color_enabled[BACK]); + + //$2132 + item("$2132", ""); + item("Color Constant - Blue", (unsigned)regs.color_b); + item("Color Constant - Green", (unsigned)regs.color_g); + item("Color Constant - Red", (unsigned)regs.color_r); + + //$2133 + item("$2133", ""); + item("Mode 7 EXTBG", regs.mode7_extbg); + item("Pseudo Hires", regs.pseudo_hires); + item("Overscan", regs.overscan); + item("OAM Interlace", regs.oam_interlace); + item("Interlace", regs.interlace); + + //$213c + item("$213c", ""); + item("H-counter", (unsigned)hcounter()); + + //$213d + item("$213d", ""); + item("V-counter", (unsigned)vcounter()); + + //$213e + item("$213e", ""); + item("Range Over", regs.range_over); + item("Time Over", regs.time_over); + item("S-PPU1 Version", (unsigned)ppu1_version); + + //$213f + item("$213f", ""); + item("Field", cpu.field()); + item("Region", !region ? "NTSC" : "PAL"); + item("S-PPU2 Version", (unsigned)ppu2_version); + + #undef item + return false; +} + +#endif diff --git a/snes/alt/ppu-compatibility/debugger/debugger.hpp b/snes/alt/ppu-compatibility/debugger/debugger.hpp new file mode 100755 index 00000000..f4ef8f51 --- /dev/null +++ b/snes/alt/ppu-compatibility/debugger/debugger.hpp @@ -0,0 +1,15 @@ +class PPUDebugger : public PPU, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + uint8 vram_mmio_read(uint16 addr); + void vram_mmio_write(uint16 addr, uint8 data); + + uint8 oam_mmio_read(uint16 addr); + void oam_mmio_write(uint16 addr, uint8 data); + + uint8 cgram_mmio_read(uint16 addr); + void cgram_mmio_write(uint16 addr, uint8 data); + + PPUDebugger(); +}; diff --git a/snes/alt/ppu-compatibility/memory/memory.cpp b/snes/alt/ppu-compatibility/memory/memory.cpp new file mode 100755 index 00000000..3f120d84 --- /dev/null +++ b/snes/alt/ppu-compatibility/memory/memory.cpp @@ -0,0 +1,157 @@ +#ifdef PPU_CPP + +void PPU::latch_counters() { + regs.hcounter = cpu.hdot(); + regs.vcounter = cpu.vcounter(); + regs.counters_latched = true; +} + +uint16 PPU::get_vram_address() { + uint16 addr = regs.vram_addr; + switch(regs.vram_mapping) { + case 0: break; //direct mapping + case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break; + case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break; + case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break; + } + return (addr << 1); +} + +//NOTE: all VRAM writes during active display are invalid. Unlike OAM and CGRAM, they will +//not be written anywhere at all. The below address ranges for where writes are invalid have +//been validated on hardware, as has the edge case where the S-CPU MDR can be written if the +//write occurs during the very last clock cycle of vblank. + +uint8 PPU::vram_mmio_read(uint16 addr) { + uint8 data; + + if(regs.display_disabled == true) { + data = vram[addr]; + } else { + uint16 v = cpu.vcounter(); + uint16 h = cpu.hcounter(); + uint16 ls = ((system.region() == System::Region::NTSC ? 525 : 625) >> 1) - 1; + if(interlace() && !cpu.field()) ls++; + + if(v == ls && h == 1362) { + data = 0x00; + } else if(v < (!overscan() ? 224 : 239)) { + data = 0x00; + } else if(v == (!overscan() ? 224 : 239)) { + if(h == 1362) { + data = vram[addr]; + } else { + data = 0x00; + } + } else { + data = vram[addr]; + } + } + + return data; +} + +void PPU::vram_mmio_write(uint16 addr, uint8 data) { + if(regs.display_disabled == true) { + vram[addr] = data; + } else { + uint16 v = cpu.vcounter(); + uint16 h = cpu.hcounter(); + if(v == 0) { + if(h <= 4) { + vram[addr] = data; + } else if(h == 6) { + vram[addr] = cpu.regs.mdr; + } else { + //no write + } + } else if(v < (!overscan() ? 225 : 240)) { + //no write + } else if(v == (!overscan() ? 225 : 240)) { + if(h <= 4) { + //no write + } else { + vram[addr] = data; + } + } else { + vram[addr] = data; + } + } +} + +uint8 PPU::oam_mmio_read(uint16 addr) { + addr &= 0x03ff; + if(addr & 0x0200) addr &= 0x021f; + uint8 data; + + if(regs.display_disabled == true) { + data = oam[addr]; + } else { + if(cpu.vcounter() < (!overscan() ? 225 : 240)) { + data = oam[regs.ioamaddr]; + } else { + data = oam[addr]; + } + } + + return data; +} + +void PPU::oam_mmio_write(uint16 addr, uint8 data) { + addr &= 0x03ff; + if(addr & 0x0200) addr &= 0x021f; + + sprite_list_valid = false; + + if(regs.display_disabled == true) { + oam[addr] = data; + update_sprite_list(addr, data); + } else { + if(cpu.vcounter() < (!overscan() ? 225 : 240)) { + oam[regs.ioamaddr] = data; + update_sprite_list(regs.ioamaddr, data); + } else { + oam[addr] = data; + update_sprite_list(addr, data); + } + } +} + +uint8 PPU::cgram_mmio_read(uint16 addr) { + addr &= 0x01ff; + uint8 data; + + if(1 || regs.display_disabled == true) { + data = cgram[addr]; + } else { + uint16 v = cpu.vcounter(); + uint16 h = cpu.hcounter(); + if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) { + data = cgram[regs.icgramaddr] & 0x7f; + } else { + data = cgram[addr]; + } + } + + if(addr & 1) data &= 0x7f; + return data; +} + +void PPU::cgram_mmio_write(uint16 addr, uint8 data) { + addr &= 0x01ff; + if(addr & 1) data &= 0x7f; + + if(1 || regs.display_disabled == true) { + cgram[addr] = data; + } else { + uint16 v = cpu.vcounter(); + uint16 h = cpu.hcounter(); + if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) { + cgram[regs.icgramaddr] = data & 0x7f; + } else { + cgram[addr] = data; + } + } +} + +#endif diff --git a/snes/alt/ppu-compatibility/memory/memory.hpp b/snes/alt/ppu-compatibility/memory/memory.hpp new file mode 100755 index 00000000..c2979aea --- /dev/null +++ b/snes/alt/ppu-compatibility/memory/memory.hpp @@ -0,0 +1,10 @@ +uint16 get_vram_address(); + +debugvirtual uint8 vram_mmio_read(uint16 addr); +debugvirtual void vram_mmio_write(uint16 addr, uint8 data); + +debugvirtual uint8 oam_mmio_read(uint16 addr); +debugvirtual void oam_mmio_write(uint16 addr, uint8 data); + +debugvirtual uint8 cgram_mmio_read(uint16 addr); +debugvirtual void cgram_mmio_write(uint16 addr, uint8 data); diff --git a/snes/alt/ppu-compatibility/mmio/mmio.cpp b/snes/alt/ppu-compatibility/mmio/mmio.cpp new file mode 100755 index 00000000..aedb67c1 --- /dev/null +++ b/snes/alt/ppu-compatibility/mmio/mmio.cpp @@ -0,0 +1,671 @@ +#ifdef PPU_CPP + +//INIDISP +void PPU::mmio_w2100(uint8 value) { + if(regs.display_disabled == true && cpu.vcounter() == (!overscan() ? 225 : 240)) { + regs.oam_addr = regs.oam_baseaddr << 1; + regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; + } + + regs.display_disabled = !!(value & 0x80); + regs.display_brightness = value & 15; +} + +//OBSEL +void PPU::mmio_w2101(uint8 value) { + regs.oam_basesize = (value >> 5) & 7; + regs.oam_nameselect = (value >> 3) & 3; + regs.oam_tdaddr = (value & 3) << 14; +} + +//OAMADDL +void PPU::mmio_w2102(uint8 data) { + regs.oam_baseaddr = (regs.oam_baseaddr & ~0xff) | (data << 0); + regs.oam_baseaddr &= 0x01ff; + regs.oam_addr = regs.oam_baseaddr << 1; + regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; +} + +//OAMADDH +void PPU::mmio_w2103(uint8 data) { + regs.oam_priority = !!(data & 0x80); + regs.oam_baseaddr = (regs.oam_baseaddr & 0xff) | (data << 8); + regs.oam_baseaddr &= 0x01ff; + regs.oam_addr = regs.oam_baseaddr << 1; + regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; +} + +//OAMDATA +void PPU::mmio_w2104(uint8 data) { + if((regs.oam_addr & 1) == 0) regs.oam_latchdata = data; + + if(regs.oam_addr & 0x0200) { + oam_mmio_write(regs.oam_addr, data); + } else if((regs.oam_addr & 1) == 1) { + oam_mmio_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata); + oam_mmio_write((regs.oam_addr & ~1) + 1, data); + } + + regs.oam_addr++; + regs.oam_addr &= 0x03ff; + regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; +} + +//BGMODE +void PPU::mmio_w2105(uint8 value) { + regs.bg_tilesize[BG4] = !!(value & 0x80); + regs.bg_tilesize[BG3] = !!(value & 0x40); + regs.bg_tilesize[BG2] = !!(value & 0x20); + regs.bg_tilesize[BG1] = !!(value & 0x10); + regs.bg3_priority = !!(value & 0x08); + regs.bg_mode = (value & 7); +} + +//MOSAIC +void PPU::mmio_w2106(uint8 value) { + regs.mosaic_size = (value >> 4) & 15; + regs.mosaic_enabled[BG4] = !!(value & 0x08); + regs.mosaic_enabled[BG3] = !!(value & 0x04); + regs.mosaic_enabled[BG2] = !!(value & 0x02); + regs.mosaic_enabled[BG1] = !!(value & 0x01); +} + +//BG1SC +void PPU::mmio_w2107(uint8 value) { + regs.bg_scaddr[BG1] = (value & 0x7c) << 9; + regs.bg_scsize[BG1] = value & 3; +} + +//BG2SC +void PPU::mmio_w2108(uint8 value) { + regs.bg_scaddr[BG2] = (value & 0x7c) << 9; + regs.bg_scsize[BG2] = value & 3; +} + +//BG3SC +void PPU::mmio_w2109(uint8 value) { + regs.bg_scaddr[BG3] = (value & 0x7c) << 9; + regs.bg_scsize[BG3] = value & 3; +} + +//BG4SC +void PPU::mmio_w210a(uint8 value) { + regs.bg_scaddr[BG4] = (value & 0x7c) << 9; + regs.bg_scsize[BG4] = value & 3; +} + +//BG12NBA +void PPU::mmio_w210b(uint8 value) { + regs.bg_tdaddr[BG1] = (value & 0x07) << 13; + regs.bg_tdaddr[BG2] = (value & 0x70) << 9; +} + +//BG34NBA +void PPU::mmio_w210c(uint8 value) { + regs.bg_tdaddr[BG3] = (value & 0x07) << 13; + regs.bg_tdaddr[BG4] = (value & 0x70) << 9; +} + +//BG1HOFS +void PPU::mmio_w210d(uint8 value) { + regs.m7_hofs = (value << 8) | regs.m7_latch; + regs.m7_latch = value; + + regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG1] >> 8) & 7); + regs.bg_ofslatch = value; +} + +//BG1VOFS +void PPU::mmio_w210e(uint8 value) { + regs.m7_vofs = (value << 8) | regs.m7_latch; + regs.m7_latch = value; + + regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch); + regs.bg_ofslatch = value; +} + +//BG2HOFS +void PPU::mmio_w210f(uint8 value) { + regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG2] >> 8) & 7); + regs.bg_ofslatch = value; +} + +//BG2VOFS +void PPU::mmio_w2110(uint8 value) { + regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch); + regs.bg_ofslatch = value; +} + +//BG3HOFS +void PPU::mmio_w2111(uint8 value) { + regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG3] >> 8) & 7); + regs.bg_ofslatch = value; +} + +//BG3VOFS +void PPU::mmio_w2112(uint8 value) { + regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch); + regs.bg_ofslatch = value; +} + +//BG4HOFS +void PPU::mmio_w2113(uint8 value) { + regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG4] >> 8) & 7); + regs.bg_ofslatch = value; +} + +//BG4VOFS +void PPU::mmio_w2114(uint8 value) { + regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch); + regs.bg_ofslatch = value; +} + +//VMAIN +void PPU::mmio_w2115(uint8 value) { + regs.vram_incmode = !!(value & 0x80); + regs.vram_mapping = (value >> 2) & 3; + switch(value & 3) { + case 0: regs.vram_incsize = 1; break; + case 1: regs.vram_incsize = 32; break; + case 2: regs.vram_incsize = 128; break; + case 3: regs.vram_incsize = 128; break; + } +} + +//VMADDL +void PPU::mmio_w2116(uint8 value) { + regs.vram_addr = (regs.vram_addr & 0xff00) | value; + uint16 addr = get_vram_address(); + regs.vram_readbuffer = vram_mmio_read(addr + 0); + regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8; +} + +//VMADDH +void PPU::mmio_w2117(uint8 value) { + regs.vram_addr = (value << 8) | (regs.vram_addr & 0x00ff); + uint16 addr = get_vram_address(); + regs.vram_readbuffer = vram_mmio_read(addr + 0); + regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8; +} + +//VMDATAL +void PPU::mmio_w2118(uint8 value) { +uint16 addr = get_vram_address(); + vram_mmio_write(addr, value); + bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1; + bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1; + bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1; + + if(regs.vram_incmode == 0) { + regs.vram_addr += regs.vram_incsize; + } +} + +//VMDATAH +void PPU::mmio_w2119(uint8 value) { +uint16 addr = get_vram_address() + 1; + vram_mmio_write(addr, value); + bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1; + bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1; + bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1; + + if(regs.vram_incmode == 1) { + regs.vram_addr += regs.vram_incsize; + } +} + +//M7SEL +void PPU::mmio_w211a(uint8 value) { + regs.mode7_repeat = (value >> 6) & 3; + regs.mode7_vflip = !!(value & 0x02); + regs.mode7_hflip = !!(value & 0x01); +} + +//M7A +void PPU::mmio_w211b(uint8 value) { + regs.m7a = (value << 8) | regs.m7_latch; + regs.m7_latch = value; +} + +//M7B +void PPU::mmio_w211c(uint8 value) { + regs.m7b = (value << 8) | regs.m7_latch; + regs.m7_latch = value; +} + +//M7C +void PPU::mmio_w211d(uint8 value) { + regs.m7c = (value << 8) | regs.m7_latch; + regs.m7_latch = value; +} + +//M7D +void PPU::mmio_w211e(uint8 value) { + regs.m7d = (value << 8) | regs.m7_latch; + regs.m7_latch = value; +} + +//M7X +void PPU::mmio_w211f(uint8 value) { + regs.m7x = (value << 8) | regs.m7_latch; + regs.m7_latch = value; +} + +//M7Y +void PPU::mmio_w2120(uint8 value) { + regs.m7y = (value << 8) | regs.m7_latch; + regs.m7_latch = value; +} + +//CGADD +void PPU::mmio_w2121(uint8 value) { + regs.cgram_addr = value << 1; +} + +//CGDATA +//note: CGRAM palette data format is 15-bits +//(0,bbbbb,ggggg,rrrrr). Highest bit is ignored, +//as evidenced by $213b CGRAM data reads. +// +//anomie indicates writes to CGDATA work the same +//as writes to OAMDATA's low table. need to verify +//this on hardware. +void PPU::mmio_w2122(uint8 value) { + if(!(regs.cgram_addr & 1)) { + regs.cgram_latchdata = value; + } else { + cgram_mmio_write((regs.cgram_addr & 0x01fe), regs.cgram_latchdata); + cgram_mmio_write((regs.cgram_addr & 0x01fe) + 1, value & 0x7f); + } + regs.cgram_addr++; + regs.cgram_addr &= 0x01ff; +} + +//W12SEL +void PPU::mmio_w2123(uint8 value) { + regs.window2_enabled[BG2] = !!(value & 0x80); + regs.window2_invert [BG2] = !!(value & 0x40); + regs.window1_enabled[BG2] = !!(value & 0x20); + regs.window1_invert [BG2] = !!(value & 0x10); + regs.window2_enabled[BG1] = !!(value & 0x08); + regs.window2_invert [BG1] = !!(value & 0x04); + regs.window1_enabled[BG1] = !!(value & 0x02); + regs.window1_invert [BG1] = !!(value & 0x01); +} + +//W34SEL +void PPU::mmio_w2124(uint8 value) { + regs.window2_enabled[BG4] = !!(value & 0x80); + regs.window2_invert [BG4] = !!(value & 0x40); + regs.window1_enabled[BG4] = !!(value & 0x20); + regs.window1_invert [BG4] = !!(value & 0x10); + regs.window2_enabled[BG3] = !!(value & 0x08); + regs.window2_invert [BG3] = !!(value & 0x04); + regs.window1_enabled[BG3] = !!(value & 0x02); + regs.window1_invert [BG3] = !!(value & 0x01); +} + +//WOBJSEL +void PPU::mmio_w2125(uint8 value) { + regs.window2_enabled[COL] = !!(value & 0x80); + regs.window2_invert [COL] = !!(value & 0x40); + regs.window1_enabled[COL] = !!(value & 0x20); + regs.window1_invert [COL] = !!(value & 0x10); + regs.window2_enabled[OAM] = !!(value & 0x08); + regs.window2_invert [OAM] = !!(value & 0x04); + regs.window1_enabled[OAM] = !!(value & 0x02); + regs.window1_invert [OAM] = !!(value & 0x01); +} + +//WH0 +void PPU::mmio_w2126(uint8 value) { + regs.window1_left = value; +} + +//WH1 +void PPU::mmio_w2127(uint8 value) { + regs.window1_right = value; +} + +//WH2 +void PPU::mmio_w2128(uint8 value) { + regs.window2_left = value; +} + +//WH3 +void PPU::mmio_w2129(uint8 value) { + regs.window2_right = value; +} + +//WBGLOG +void PPU::mmio_w212a(uint8 value) { + regs.window_mask[BG4] = (value >> 6) & 3; + regs.window_mask[BG3] = (value >> 4) & 3; + regs.window_mask[BG2] = (value >> 2) & 3; + regs.window_mask[BG1] = (value ) & 3; +} + +//WOBJLOG +void PPU::mmio_w212b(uint8 value) { + regs.window_mask[COL] = (value >> 2) & 3; + regs.window_mask[OAM] = (value ) & 3; +} + +//TM +void PPU::mmio_w212c(uint8 value) { + regs.bg_enabled[OAM] = !!(value & 0x10); + regs.bg_enabled[BG4] = !!(value & 0x08); + regs.bg_enabled[BG3] = !!(value & 0x04); + regs.bg_enabled[BG2] = !!(value & 0x02); + regs.bg_enabled[BG1] = !!(value & 0x01); +} + +//TS +void PPU::mmio_w212d(uint8 value) { + regs.bgsub_enabled[OAM] = !!(value & 0x10); + regs.bgsub_enabled[BG4] = !!(value & 0x08); + regs.bgsub_enabled[BG3] = !!(value & 0x04); + regs.bgsub_enabled[BG2] = !!(value & 0x02); + regs.bgsub_enabled[BG1] = !!(value & 0x01); +} + +//TMW +void PPU::mmio_w212e(uint8 value) { + regs.window_enabled[OAM] = !!(value & 0x10); + regs.window_enabled[BG4] = !!(value & 0x08); + regs.window_enabled[BG3] = !!(value & 0x04); + regs.window_enabled[BG2] = !!(value & 0x02); + regs.window_enabled[BG1] = !!(value & 0x01); +} + +//TSW +void PPU::mmio_w212f(uint8 value) { + regs.sub_window_enabled[OAM] = !!(value & 0x10); + regs.sub_window_enabled[BG4] = !!(value & 0x08); + regs.sub_window_enabled[BG3] = !!(value & 0x04); + regs.sub_window_enabled[BG2] = !!(value & 0x02); + regs.sub_window_enabled[BG1] = !!(value & 0x01); +} + +//CGWSEL +void PPU::mmio_w2130(uint8 value) { + regs.color_mask = (value >> 6) & 3; + regs.colorsub_mask = (value >> 4) & 3; + regs.addsub_mode = !!(value & 0x02); + regs.direct_color = !!(value & 0x01); +} + +//CGADDSUB +void PPU::mmio_w2131(uint8 value) { + regs.color_mode = !!(value & 0x80); + regs.color_halve = !!(value & 0x40); + regs.color_enabled[BACK] = !!(value & 0x20); + regs.color_enabled[OAM] = !!(value & 0x10); + regs.color_enabled[BG4] = !!(value & 0x08); + regs.color_enabled[BG3] = !!(value & 0x04); + regs.color_enabled[BG2] = !!(value & 0x02); + regs.color_enabled[BG1] = !!(value & 0x01); +} + +//COLDATA +void PPU::mmio_w2132(uint8 value) { + if(value & 0x80) regs.color_b = value & 0x1f; + if(value & 0x40) regs.color_g = value & 0x1f; + if(value & 0x20) regs.color_r = value & 0x1f; + + regs.color_rgb = (regs.color_r) + | (regs.color_g << 5) + | (regs.color_b << 10); +} + +//SETINI +void PPU::mmio_w2133(uint8 value) { + regs.mode7_extbg = !!(value & 0x40); + regs.pseudo_hires = !!(value & 0x08); + regs.overscan = !!(value & 0x04); + regs.oam_interlace = !!(value & 0x02); + regs.interlace = !!(value & 0x01); + + display.overscan = regs.overscan; + sprite_list_valid = false; +} + +//MPYL +uint8 PPU::mmio_r2134() { +uint32 r; + r = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = r; + return regs.ppu1_mdr; +} + +//MPYM +uint8 PPU::mmio_r2135() { +uint32 r; + r = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = r >> 8; + return regs.ppu1_mdr; +} + +//MPYH +uint8 PPU::mmio_r2136() { +uint32 r; + r = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = r >> 16; + return regs.ppu1_mdr; +} + +//SLHV +uint8 PPU::mmio_r2137() { + if(cpu.pio() & 0x80) { + latch_counters(); + } + return cpu.regs.mdr; +} + +//OAMDATAREAD +uint8 PPU::mmio_r2138() { + regs.ppu1_mdr = oam_mmio_read(regs.oam_addr); + + regs.oam_addr++; + regs.oam_addr &= 0x03ff; + regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; + + return regs.ppu1_mdr; +} + +//VMDATALREAD +uint8 PPU::mmio_r2139() { +uint16 addr = get_vram_address(); + regs.ppu1_mdr = regs.vram_readbuffer; + if(regs.vram_incmode == 0) { + addr &= 0xfffe; + regs.vram_readbuffer = vram_mmio_read(addr + 0); + regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8; + regs.vram_addr += regs.vram_incsize; + } + return regs.ppu1_mdr; +} + +//VMDATAHREAD +uint8 PPU::mmio_r213a() { +uint16 addr = get_vram_address() + 1; + regs.ppu1_mdr = regs.vram_readbuffer >> 8; + if(regs.vram_incmode == 1) { + addr &= 0xfffe; + regs.vram_readbuffer = vram_mmio_read(addr + 0); + regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8; + regs.vram_addr += regs.vram_incsize; + } + return regs.ppu1_mdr; +} + +//CGDATAREAD +//note: CGRAM palette data is 15-bits (0,bbbbb,ggggg,rrrrr) +//therefore, the high byte read from each color does not +//update bit 7 of the PPU2 MDR. +uint8 PPU::mmio_r213b() { + if(!(regs.cgram_addr & 1)) { + regs.ppu2_mdr = cgram_mmio_read(regs.cgram_addr) & 0xff; + } else { + regs.ppu2_mdr &= 0x80; + regs.ppu2_mdr |= cgram_mmio_read(regs.cgram_addr) & 0x7f; + } + regs.cgram_addr++; + regs.cgram_addr &= 0x01ff; + return regs.ppu2_mdr; +} + +//OPHCT +uint8 PPU::mmio_r213c() { + if(!regs.latch_hcounter) { + regs.ppu2_mdr = regs.hcounter & 0xff; + } else { + regs.ppu2_mdr &= 0xfe; + regs.ppu2_mdr |= (regs.hcounter >> 8) & 1; + } + regs.latch_hcounter ^= 1; + return regs.ppu2_mdr; +} + +//OPVCT +uint8 PPU::mmio_r213d() { + if(!regs.latch_vcounter) { + regs.ppu2_mdr = regs.vcounter & 0xff; + } else { + regs.ppu2_mdr &= 0xfe; + regs.ppu2_mdr |= (regs.vcounter >> 8) & 1; + } + regs.latch_vcounter ^= 1; + return regs.ppu2_mdr; +} + +//STAT77 +uint8 PPU::mmio_r213e() { +uint8 r = 0x00; + r |= (regs.time_over) ? 0x80 : 0x00; + r |= (regs.range_over) ? 0x40 : 0x00; + r |= (regs.ppu1_mdr & 0x10); + r |= (ppu1_version & 0x0f); + regs.ppu1_mdr = r; + return regs.ppu1_mdr; +} + +//STAT78 +uint8 PPU::mmio_r213f() { +uint8 r = 0x00; + regs.latch_hcounter = 0; + regs.latch_vcounter = 0; + + r |= cpu.field() << 7; + if(!(cpu.pio() & 0x80)) { + r |= 0x40; + } else if(regs.counters_latched == true) { + r |= 0x40; + regs.counters_latched = false; + } + r |= (regs.ppu2_mdr & 0x20); + r |= (region << 4); //0 = NTSC, 1 = PAL + r |= (ppu2_version & 0x0f); + regs.ppu2_mdr = r; + return regs.ppu2_mdr; +} + +uint8 PPU::mmio_read(unsigned addr) { + cpu.synchronize_ppu(); + + switch(addr & 0xffff) { + case 0x2104: + case 0x2105: + case 0x2106: + case 0x2108: + case 0x2109: + case 0x210a: + case 0x2114: + case 0x2115: + case 0x2116: + case 0x2118: + case 0x2119: + case 0x211a: + case 0x2124: + case 0x2125: + case 0x2126: + case 0x2128: + case 0x2129: + case 0x212a: return regs.ppu1_mdr; + case 0x2134: return mmio_r2134(); //MPYL + case 0x2135: return mmio_r2135(); //MPYM + case 0x2136: return mmio_r2136(); //MPYH + case 0x2137: return mmio_r2137(); //SLHV + case 0x2138: return mmio_r2138(); //OAMDATAREAD + case 0x2139: return mmio_r2139(); //VMDATALREAD + case 0x213a: return mmio_r213a(); //VMDATAHREAD + case 0x213b: return mmio_r213b(); //CGDATAREAD + case 0x213c: return mmio_r213c(); //OPHCT + case 0x213d: return mmio_r213d(); //OPVCT + case 0x213e: return mmio_r213e(); //STAT77 + case 0x213f: return mmio_r213f(); //STAT78 + } + + return cpu.regs.mdr; +} + +void PPU::mmio_write(unsigned addr, uint8 data) { + cpu.synchronize_ppu(); + + switch(addr & 0xffff) { + case 0x2100: return mmio_w2100(data); //INIDISP + case 0x2101: return mmio_w2101(data); //OBSEL + case 0x2102: return mmio_w2102(data); //OAMADDL + case 0x2103: return mmio_w2103(data); //OAMADDH + case 0x2104: return mmio_w2104(data); //OAMDATA + case 0x2105: return mmio_w2105(data); //BGMODE + case 0x2106: return mmio_w2106(data); //MOSAIC + case 0x2107: return mmio_w2107(data); //BG1SC + case 0x2108: return mmio_w2108(data); //BG2SC + case 0x2109: return mmio_w2109(data); //BG3SC + case 0x210a: return mmio_w210a(data); //BG4SC + case 0x210b: return mmio_w210b(data); //BG12NBA + case 0x210c: return mmio_w210c(data); //BG34NBA + case 0x210d: return mmio_w210d(data); //BG1HOFS + case 0x210e: return mmio_w210e(data); //BG1VOFS + case 0x210f: return mmio_w210f(data); //BG2HOFS + case 0x2110: return mmio_w2110(data); //BG2VOFS + case 0x2111: return mmio_w2111(data); //BG3HOFS + case 0x2112: return mmio_w2112(data); //BG3VOFS + case 0x2113: return mmio_w2113(data); //BG4HOFS + case 0x2114: return mmio_w2114(data); //BG4VOFS + case 0x2115: return mmio_w2115(data); //VMAIN + case 0x2116: return mmio_w2116(data); //VMADDL + case 0x2117: return mmio_w2117(data); //VMADDH + case 0x2118: return mmio_w2118(data); //VMDATAL + case 0x2119: return mmio_w2119(data); //VMDATAH + case 0x211a: return mmio_w211a(data); //M7SEL + case 0x211b: return mmio_w211b(data); //M7A + case 0x211c: return mmio_w211c(data); //M7B + case 0x211d: return mmio_w211d(data); //M7C + case 0x211e: return mmio_w211e(data); //M7D + case 0x211f: return mmio_w211f(data); //M7X + case 0x2120: return mmio_w2120(data); //M7Y + case 0x2121: return mmio_w2121(data); //CGADD + case 0x2122: return mmio_w2122(data); //CGDATA + case 0x2123: return mmio_w2123(data); //W12SEL + case 0x2124: return mmio_w2124(data); //W34SEL + case 0x2125: return mmio_w2125(data); //WOBJSEL + case 0x2126: return mmio_w2126(data); //WH0 + case 0x2127: return mmio_w2127(data); //WH1 + case 0x2128: return mmio_w2128(data); //WH2 + case 0x2129: return mmio_w2129(data); //WH3 + case 0x212a: return mmio_w212a(data); //WBGLOG + case 0x212b: return mmio_w212b(data); //WOBJLOG + case 0x212c: return mmio_w212c(data); //TM + case 0x212d: return mmio_w212d(data); //TS + case 0x212e: return mmio_w212e(data); //TMW + case 0x212f: return mmio_w212f(data); //TSW + case 0x2130: return mmio_w2130(data); //CGWSEL + case 0x2131: return mmio_w2131(data); //CGADDSUB + case 0x2132: return mmio_w2132(data); //COLDATA + case 0x2133: return mmio_w2133(data); //SETINI + } +} + +#endif diff --git a/snes/alt/ppu-compatibility/mmio/mmio.hpp b/snes/alt/ppu-compatibility/mmio/mmio.hpp new file mode 100755 index 00000000..aeb1c3a6 --- /dev/null +++ b/snes/alt/ppu-compatibility/mmio/mmio.hpp @@ -0,0 +1,202 @@ +struct { + //open bus support + uint8 ppu1_mdr, ppu2_mdr; + + //bg line counters + uint16 bg_y[4]; + + //internal state + uint16 ioamaddr; + uint16 icgramaddr; + + //$2100 + bool display_disabled; + uint8 display_brightness; + + //$2101 + uint8 oam_basesize; + uint8 oam_nameselect; + uint16 oam_tdaddr; + + //$2102-$2103 + uint16 oam_baseaddr; + uint16 oam_addr; + bool oam_priority; + uint8 oam_firstsprite; + + //$2104 + uint8 oam_latchdata; + + //$2105 + bool bg_tilesize[4]; + bool bg3_priority; + uint8 bg_mode; + + //$2106 + uint8 mosaic_size; + bool mosaic_enabled[4]; + uint16 mosaic_countdown; + + //$2107-$210a + uint16 bg_scaddr[4]; + uint8 bg_scsize[4]; + + //$210b-$210c + uint16 bg_tdaddr[4]; + + //$210d-$2114 + uint8 bg_ofslatch; + uint16 m7_hofs, m7_vofs; + uint16 bg_hofs[4]; + uint16 bg_vofs[4]; + + //$2115 + bool vram_incmode; + uint8 vram_mapping; + uint8 vram_incsize; + + //$2116-$2117 + uint16 vram_addr; + + //$211a + uint8 mode7_repeat; + bool mode7_vflip; + bool mode7_hflip; + + //$211b-$2120 + uint8 m7_latch; + uint16 m7a, m7b, m7c, m7d, m7x, m7y; + + //$2121 + uint16 cgram_addr; + + //$2122 + uint8 cgram_latchdata; + + //$2123-$2125 + bool window1_enabled[6]; + bool window1_invert [6]; + bool window2_enabled[6]; + bool window2_invert [6]; + + //$2126-$2129 + uint8 window1_left, window1_right; + uint8 window2_left, window2_right; + + //$212a-$212b + uint8 window_mask[6]; + + //$212c-$212d + bool bg_enabled[5], bgsub_enabled[5]; + + //$212e-$212f + bool window_enabled[5], sub_window_enabled[5]; + + //$2130 + uint8 color_mask, colorsub_mask; + bool addsub_mode; + bool direct_color; + + //$2131 + bool color_mode, color_halve; + bool color_enabled[6]; + + //$2132 + uint8 color_r, color_g, color_b; + uint16 color_rgb; + + //$2133 + //overscan and interlace are checked once per frame to + //determine if entire frame should be interlaced/non-interlace + //and overscan adjusted. therefore, the variables act sort of + //like a buffer, but they do still affect internal rendering + bool mode7_extbg; + bool pseudo_hires; + bool overscan; + uint16 scanlines; + bool oam_interlace; + bool interlace; + + //$2137 + uint16 hcounter, vcounter; + bool latch_hcounter, latch_vcounter; + bool counters_latched; + + //$2139-$213a + uint16 vram_readbuffer; + + //$213e + bool time_over, range_over; + uint16 oam_itemcount, oam_tilecount; +} regs; + +void mmio_w2100(uint8 value); //INIDISP +void mmio_w2101(uint8 value); //OBSEL +void mmio_w2102(uint8 value); //OAMADDL +void mmio_w2103(uint8 value); //OAMADDH +void mmio_w2104(uint8 value); //OAMDATA +void mmio_w2105(uint8 value); //BGMODE +void mmio_w2106(uint8 value); //MOSAIC +void mmio_w2107(uint8 value); //BG1SC +void mmio_w2108(uint8 value); //BG2SC +void mmio_w2109(uint8 value); //BG3SC +void mmio_w210a(uint8 value); //BG4SC +void mmio_w210b(uint8 value); //BG12NBA +void mmio_w210c(uint8 value); //BG34NBA +void mmio_w210d(uint8 value); //BG1HOFS +void mmio_w210e(uint8 value); //BG1VOFS +void mmio_w210f(uint8 value); //BG2HOFS +void mmio_w2110(uint8 value); //BG2VOFS +void mmio_w2111(uint8 value); //BG3HOFS +void mmio_w2112(uint8 value); //BG3VOFS +void mmio_w2113(uint8 value); //BG4HOFS +void mmio_w2114(uint8 value); //BG4VOFS +void mmio_w2115(uint8 value); //VMAIN +void mmio_w2116(uint8 value); //VMADDL +void mmio_w2117(uint8 value); //VMADDH +void mmio_w2118(uint8 value); //VMDATAL +void mmio_w2119(uint8 value); //VMDATAH +void mmio_w211a(uint8 value); //M7SEL +void mmio_w211b(uint8 value); //M7A +void mmio_w211c(uint8 value); //M7B +void mmio_w211d(uint8 value); //M7C +void mmio_w211e(uint8 value); //M7D +void mmio_w211f(uint8 value); //M7X +void mmio_w2120(uint8 value); //M7Y +void mmio_w2121(uint8 value); //CGADD +void mmio_w2122(uint8 value); //CGDATA +void mmio_w2123(uint8 value); //W12SEL +void mmio_w2124(uint8 value); //W34SEL +void mmio_w2125(uint8 value); //WOBJSEL +void mmio_w2126(uint8 value); //WH0 +void mmio_w2127(uint8 value); //WH1 +void mmio_w2128(uint8 value); //WH2 +void mmio_w2129(uint8 value); //WH3 +void mmio_w212a(uint8 value); //WBGLOG +void mmio_w212b(uint8 value); //WOBJLOG +void mmio_w212c(uint8 value); //TM +void mmio_w212d(uint8 value); //TS +void mmio_w212e(uint8 value); //TMW +void mmio_w212f(uint8 value); //TSW +void mmio_w2130(uint8 value); //CGWSEL +void mmio_w2131(uint8 value); //CGADDSUB +void mmio_w2132(uint8 value); //COLDATA +void mmio_w2133(uint8 value); //SETINI + +uint8 mmio_r2134(); //MPYL +uint8 mmio_r2135(); //MPYM +uint8 mmio_r2136(); //MPYH +uint8 mmio_r2137(); //SLHV +uint8 mmio_r2138(); //OAMDATAREAD +uint8 mmio_r2139(); //VMDATALREAD +uint8 mmio_r213a(); //VMDATAHREAD +uint8 mmio_r213b(); //CGDATAREAD +uint8 mmio_r213c(); //OPHCT +uint8 mmio_r213d(); //OPVCT +uint8 mmio_r213e(); //STAT77 +uint8 mmio_r213f(); //STAT78 + +uint8 mmio_read(unsigned addr); +void mmio_write(unsigned addr, uint8 data); + +void latch_counters(); diff --git a/snes/alt/ppu-compatibility/ppu.cpp b/snes/alt/ppu-compatibility/ppu.cpp new file mode 100755 index 00000000..1a3835b3 --- /dev/null +++ b/snes/alt/ppu-compatibility/ppu.cpp @@ -0,0 +1,434 @@ +#include + +#define PPU_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + PPUDebugger ppu; +#else + PPU ppu; +#endif + +#include "memory/memory.cpp" +#include "mmio/mmio.cpp" +#include "render/render.cpp" +#include "serialization.cpp" + +void PPU::step(unsigned clocks) { + clock += clocks; +} + +void PPU::synchronize_cpu() { + if(CPU::Threaded == true) { + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +} + +void PPU::Enter() { ppu.enter(); } + +void PPU::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + //H = 0 (initialize) + scanline(); + add_clocks(10); + + //H = 10 (cache mode7 registers + OAM address reset) + cache.m7_hofs = regs.m7_hofs; + cache.m7_vofs = regs.m7_vofs; + cache.m7a = regs.m7a; + cache.m7b = regs.m7b; + cache.m7c = regs.m7c; + cache.m7d = regs.m7d; + cache.m7x = regs.m7x; + cache.m7y = regs.m7y; + if(vcounter() == (!overscan() ? 225 : 240)) { + if(regs.display_disabled == false) { + regs.oam_addr = regs.oam_baseaddr << 1; + regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127; + } + } + add_clocks(502); + + //H = 512 (render) + render_scanline(); + add_clocks(640); + + //H = 1152 (cache OBSEL) + if(cache.oam_basesize != regs.oam_basesize) { + cache.oam_basesize = regs.oam_basesize; + sprite_list_valid = false; + } + cache.oam_nameselect = regs.oam_nameselect; + cache.oam_tdaddr = regs.oam_tdaddr; + add_clocks(lineclocks() - 1152); //seek to start of next scanline + + } +} + +void PPU::add_clocks(unsigned clocks) { + tick(clocks); + step(clocks); + synchronize_cpu(); +} + +void PPU::scanline() { + line = vcounter(); + + if(line == 0) { + frame(); + + //RTO flag reset + regs.time_over = false; + regs.range_over = false; + } + + if(line == 1) { + //mosaic reset + for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1; + regs.mosaic_countdown = regs.mosaic_size + 1; + regs.mosaic_countdown--; + } else { + for(int bg = BG1; bg <= BG4; bg++) { + if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line; + } + if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1; + regs.mosaic_countdown--; + } +} + +void PPU::render_scanline() { + if(line >= 1 && line < (!overscan() ? 225 : 240)) { + if(framecounter) return; + render_line_oam_rto(); + render_line(); + } +} + +void PPU::frame() { + system.frame(); + + if(field() == 0) { + display.interlace = regs.interlace; + regs.scanlines = (regs.overscan == false) ? 224 : 239; + } + + framecounter = (frameskip == 0 ? 0 : (framecounter + 1) % frameskip); +} + +void PPU::enable() { + function read = { &PPU::mmio_read, (PPU*)&ppu }; + function write = { &PPU::mmio_write, (PPU*)&ppu }; + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write); +} + +void PPU::power() { + ppu1_version = config.ppu1.version; + ppu2_version = config.ppu2.version; + + for(auto &n : vram) n = 0x00; + for(auto &n : oam) n = 0x00; + for(auto &n : cgram) n = 0x00; + flush_tiledata_cache(); + + region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL + + regs.ioamaddr = 0x0000; + regs.icgramaddr = 0x01ff; + + //$2100 + regs.display_disabled = true; + regs.display_brightness = 15; + + //$2101 + regs.oam_basesize = 0; + regs.oam_nameselect = 0; + regs.oam_tdaddr = 0x0000; + + cache.oam_basesize = 0; + cache.oam_nameselect = 0; + cache.oam_tdaddr = 0x0000; + + //$2102-$2103 + regs.oam_baseaddr = 0x0000; + regs.oam_addr = 0x0000; + regs.oam_priority = false; + regs.oam_firstsprite = 0; + + //$2104 + regs.oam_latchdata = 0x00; + + //$2105 + regs.bg_tilesize[BG1] = 0; + regs.bg_tilesize[BG2] = 0; + regs.bg_tilesize[BG3] = 0; + regs.bg_tilesize[BG4] = 0; + regs.bg3_priority = 0; + regs.bg_mode = 0; + + //$2106 + regs.mosaic_size = 0; + regs.mosaic_enabled[BG1] = false; + regs.mosaic_enabled[BG2] = false; + regs.mosaic_enabled[BG3] = false; + regs.mosaic_enabled[BG4] = false; + regs.mosaic_countdown = 0; + + //$2107-$210a + regs.bg_scaddr[BG1] = 0x0000; + regs.bg_scaddr[BG2] = 0x0000; + regs.bg_scaddr[BG3] = 0x0000; + regs.bg_scaddr[BG4] = 0x0000; + regs.bg_scsize[BG1] = SC_32x32; + regs.bg_scsize[BG2] = SC_32x32; + regs.bg_scsize[BG3] = SC_32x32; + regs.bg_scsize[BG4] = SC_32x32; + + //$210b-$210c + regs.bg_tdaddr[BG1] = 0x0000; + regs.bg_tdaddr[BG2] = 0x0000; + regs.bg_tdaddr[BG3] = 0x0000; + regs.bg_tdaddr[BG4] = 0x0000; + + //$210d-$2114 + regs.bg_ofslatch = 0x00; + regs.m7_hofs = regs.m7_vofs = 0x0000; + regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000; + regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000; + regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000; + regs.bg_hofs[BG4] = regs.bg_vofs[BG4] = 0x0000; + + //$2115 + regs.vram_incmode = 1; + regs.vram_mapping = 0; + regs.vram_incsize = 1; + + //$2116-$2117 + regs.vram_addr = 0x0000; + + //$211a + regs.mode7_repeat = 0; + regs.mode7_vflip = false; + regs.mode7_hflip = false; + + //$211b-$2120 + regs.m7_latch = 0x00; + regs.m7a = 0x0000; + regs.m7b = 0x0000; + regs.m7c = 0x0000; + regs.m7d = 0x0000; + regs.m7x = 0x0000; + regs.m7y = 0x0000; + + //$2121 + regs.cgram_addr = 0x0000; + + //$2122 + regs.cgram_latchdata = 0x00; + + //$2123-$2125 + regs.window1_enabled[BG1] = false; + regs.window1_enabled[BG2] = false; + regs.window1_enabled[BG3] = false; + regs.window1_enabled[BG4] = false; + regs.window1_enabled[OAM] = false; + regs.window1_enabled[COL] = false; + + regs.window1_invert [BG1] = false; + regs.window1_invert [BG2] = false; + regs.window1_invert [BG3] = false; + regs.window1_invert [BG4] = false; + regs.window1_invert [OAM] = false; + regs.window1_invert [COL] = false; + + regs.window2_enabled[BG1] = false; + regs.window2_enabled[BG2] = false; + regs.window2_enabled[BG3] = false; + regs.window2_enabled[BG4] = false; + regs.window2_enabled[OAM] = false; + regs.window2_enabled[COL] = false; + + regs.window2_invert [BG1] = false; + regs.window2_invert [BG2] = false; + regs.window2_invert [BG3] = false; + regs.window2_invert [BG4] = false; + regs.window2_invert [OAM] = false; + regs.window2_invert [COL] = false; + + //$2126-$2129 + regs.window1_left = 0x00; + regs.window1_right = 0x00; + regs.window2_left = 0x00; + regs.window2_right = 0x00; + + //$212a-$212b + regs.window_mask[BG1] = 0; + regs.window_mask[BG2] = 0; + regs.window_mask[BG3] = 0; + regs.window_mask[BG4] = 0; + regs.window_mask[OAM] = 0; + regs.window_mask[COL] = 0; + + //$212c-$212d + regs.bg_enabled[BG1] = false; + regs.bg_enabled[BG2] = false; + regs.bg_enabled[BG3] = false; + regs.bg_enabled[BG4] = false; + regs.bg_enabled[OAM] = false; + regs.bgsub_enabled[BG1] = false; + regs.bgsub_enabled[BG2] = false; + regs.bgsub_enabled[BG3] = false; + regs.bgsub_enabled[BG4] = false; + regs.bgsub_enabled[OAM] = false; + + //$212e-$212f + regs.window_enabled[BG1] = false; + regs.window_enabled[BG2] = false; + regs.window_enabled[BG3] = false; + regs.window_enabled[BG4] = false; + regs.window_enabled[OAM] = false; + regs.sub_window_enabled[BG1] = false; + regs.sub_window_enabled[BG2] = false; + regs.sub_window_enabled[BG3] = false; + regs.sub_window_enabled[BG4] = false; + regs.sub_window_enabled[OAM] = false; + + //$2130 + regs.color_mask = 0; + regs.colorsub_mask = 0; + regs.addsub_mode = false; + regs.direct_color = false; + + //$2131 + regs.color_mode = 0; + regs.color_halve = false; + regs.color_enabled[BACK] = false; + regs.color_enabled[OAM] = false; + regs.color_enabled[BG4] = false; + regs.color_enabled[BG3] = false; + regs.color_enabled[BG2] = false; + regs.color_enabled[BG1] = false; + + //$2132 + regs.color_r = 0x00; + regs.color_g = 0x00; + regs.color_b = 0x00; + regs.color_rgb = 0x0000; + + //$2133 + regs.mode7_extbg = false; + regs.pseudo_hires = false; + regs.overscan = false; + regs.scanlines = 224; + regs.oam_interlace = false; + regs.interlace = false; + + //$2137 + regs.hcounter = 0; + regs.vcounter = 0; + regs.latch_hcounter = 0; + regs.latch_vcounter = 0; + regs.counters_latched = false; + + //$2139-$213a + regs.vram_readbuffer = 0x0000; + + //$213e + regs.time_over = false; + regs.range_over = false; + + reset(); +} + +void PPU::reset() { + create(Enter, system.cpu_frequency()); + PPUcounter::reset(); + memset(surface, 0, 512 * 512 * sizeof(uint32)); + + frame(); + + //$2100 + regs.display_disabled = true; + + display.interlace = false; + display.overscan = false; + regs.scanlines = 224; + + memset(sprite_list, 0, sizeof(sprite_list)); + sprite_list_valid = false; + + //open bus support + regs.ppu1_mdr = 0xff; + regs.ppu2_mdr = 0xff; + + //bg line counters + regs.bg_y[0] = 0; + regs.bg_y[1] = 0; + regs.bg_y[2] = 0; + regs.bg_y[3] = 0; +} + +void PPU::layer_enable(unsigned layer, unsigned priority, bool enable) { + switch(layer * 4 + priority) { + case 0: layer_enabled[BG1][0] = enable; break; + case 1: layer_enabled[BG1][1] = enable; break; + case 4: layer_enabled[BG2][0] = enable; break; + case 5: layer_enabled[BG2][1] = enable; break; + case 8: layer_enabled[BG3][0] = enable; break; + case 9: layer_enabled[BG3][1] = enable; break; + case 12: layer_enabled[BG4][0] = enable; break; + case 13: layer_enabled[BG4][1] = enable; break; + case 16: layer_enabled[OAM][0] = enable; break; + case 17: layer_enabled[OAM][1] = enable; break; + case 18: layer_enabled[OAM][2] = enable; break; + case 19: layer_enabled[OAM][3] = enable; break; + } +} + +void PPU::set_frameskip(unsigned frameskip_) { + frameskip = frameskip_; + framecounter = 0; +} + +PPU::PPU() { + surface = new uint32[512 * 512]; + output = surface + 16 * 512; + + alloc_tiledata_cache(); + + for(unsigned l = 0; l < 16; l++) { + for(unsigned i = 0; i < 4096; i++) { + mosaic_table[l][i] = (i / (l + 1)) * (l + 1); + } + } + + layer_enabled[BG1][0] = true; + layer_enabled[BG1][1] = true; + layer_enabled[BG2][0] = true; + layer_enabled[BG2][1] = true; + layer_enabled[BG3][0] = true; + layer_enabled[BG3][1] = true; + layer_enabled[BG4][0] = true; + layer_enabled[BG4][1] = true; + layer_enabled[OAM][0] = true; + layer_enabled[OAM][1] = true; + layer_enabled[OAM][2] = true; + layer_enabled[OAM][3] = true; + frameskip = 0; + framecounter = 0; +} + +PPU::~PPU() { + delete[] surface; + free_tiledata_cache(); +} + +} diff --git a/snes/alt/ppu-compatibility/ppu.hpp b/snes/alt/ppu-compatibility/ppu.hpp new file mode 100755 index 00000000..cccaabba --- /dev/null +++ b/snes/alt/ppu-compatibility/ppu.hpp @@ -0,0 +1,84 @@ +class PPU : public Processor, public PPUcounter { +public: + uint8 vram[128 * 1024]; + uint8 oam[544]; + uint8 cgram[512]; + + enum : bool { Threaded = true }; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_cpu(); + + #include "memory/memory.hpp" + #include "mmio/mmio.hpp" + #include "render/render.hpp" + + uint32 *surface; + uint32 *output; + + uint8 ppu1_version; + uint8 ppu2_version; + + static void Enter(); + void add_clocks(unsigned clocks); + + uint8 region; + unsigned line; + + enum { NTSC = 0, PAL = 1 }; + enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 }; + enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 }; + + struct { + bool interlace; + bool overscan; + } display; + + struct { + //$2101 + uint8 oam_basesize; + uint8 oam_nameselect; + uint16 oam_tdaddr; + + //$210d-$210e + uint16 m7_hofs, m7_vofs; + + //$211b-$2120 + uint16 m7a, m7b, m7c, m7d, m7x, m7y; + } cache; + + alwaysinline bool interlace() const { return display.interlace; } + alwaysinline bool overscan() const { return display.overscan; } + alwaysinline bool hires() const { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); } + + uint16 mosaic_table[16][4096]; + void render_line(); + + void update_oam_status(); + //required functions + void scanline(); + void render_scanline(); + void frame(); + void enter(); + void enable(); + void power(); + void reset(); + + bool layer_enabled[5][4]; + void layer_enable(unsigned layer, unsigned priority, bool enable); + unsigned frameskip; + unsigned framecounter; + void set_frameskip(unsigned frameskip); + + void serialize(serializer&); + PPU(); + ~PPU(); + + friend class PPUDebugger; +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern PPUDebugger ppu; +#else + extern PPU ppu; +#endif diff --git a/snes/alt/ppu-compatibility/render/addsub.cpp b/snes/alt/ppu-compatibility/render/addsub.cpp new file mode 100755 index 00000000..fc88bad3 --- /dev/null +++ b/snes/alt/ppu-compatibility/render/addsub.cpp @@ -0,0 +1,25 @@ +#ifdef PPU_CPP + +//color addition / subtraction +//thanks go to blargg for the optimized algorithms +inline uint16 PPU::addsub(uint32 x, uint32 y, bool halve) { + if(!regs.color_mode) { + if(!halve) { + unsigned sum = x + y; + unsigned carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; + return (sum - carry) | (carry - (carry >> 5)); + } else { + return (x + y - ((x ^ y) & 0x0421)) >> 1; + } + } else { + unsigned diff = x - y + 0x8420; + unsigned borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420; + if(!halve) { + return (diff - borrow) & (borrow - (borrow >> 5)); + } else { + return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1; + } + } +} + +#endif diff --git a/snes/alt/ppu-compatibility/render/bg.cpp b/snes/alt/ppu-compatibility/render/bg.cpp new file mode 100755 index 00000000..6793d747 --- /dev/null +++ b/snes/alt/ppu-compatibility/render/bg.cpp @@ -0,0 +1,209 @@ +#ifdef PPU_CPP + +//called once at the start of every rendered scanline +void PPU::update_bg_info() { + const unsigned hires = (regs.bg_mode == 5 || regs.bg_mode == 6); + const unsigned width = (!hires ? 256 : 512); + + for(unsigned bg = 0; bg < 4; bg++) { + bg_info[bg].th = (regs.bg_tilesize[bg] ? 4 : 3); + bg_info[bg].tw = (hires ? 4 : bg_info[bg].th); + + bg_info[bg].mx = (bg_info[bg].th == 4 ? (width << 1) : width); + bg_info[bg].my = bg_info[bg].mx; + if(regs.bg_scsize[bg] & 0x01) bg_info[bg].mx <<= 1; + if(regs.bg_scsize[bg] & 0x02) bg_info[bg].my <<= 1; + bg_info[bg].mx--; + bg_info[bg].my--; + + bg_info[bg].scy = (regs.bg_scsize[bg] & 0x02) ? (32 << 5) : 0; + bg_info[bg].scx = (regs.bg_scsize[bg] & 0x01) ? (32 << 5) : 0; + if(regs.bg_scsize[bg] == 3) bg_info[bg].scy <<= 1; + } +} + +template +uint16 PPU::bg_get_tile(uint16 x, uint16 y) { + x = (x & bg_info[bg].mx) >> bg_info[bg].tw; + y = (y & bg_info[bg].my) >> bg_info[bg].th; + + uint16 pos = ((y & 0x1f) << 5) + (x & 0x1f); + if(y & 0x20) pos += bg_info[bg].scy; + if(x & 0x20) pos += bg_info[bg].scx; + + const uint16 addr = regs.bg_scaddr[bg] + (pos << 1); + return vram[addr] + (vram[addr + 1] << 8); +} + +#define setpixel_main(x) \ + if(pixel_cache[x].pri_main < tile_pri) { \ + pixel_cache[x].pri_main = tile_pri; \ + pixel_cache[x].bg_main = bg; \ + pixel_cache[x].src_main = col; \ + pixel_cache[x].ce_main = false; \ + } + +#define setpixel_sub(x) \ + if(pixel_cache[x].pri_sub < tile_pri) { \ + pixel_cache[x].pri_sub = tile_pri; \ + pixel_cache[x].bg_sub = bg; \ + pixel_cache[x].src_sub = col; \ + pixel_cache[x].ce_sub = false; \ + } + +template +void PPU::render_line_bg(uint8 pri0_pos, uint8 pri1_pos) { + if(layer_enabled[bg][0] == false) pri0_pos = 0; + if(layer_enabled[bg][1] == false) pri1_pos = 0; + if(pri0_pos + pri1_pos == 0) return; + + if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return; + + const bool bg_enabled = regs.bg_enabled[bg]; + const bool bgsub_enabled = regs.bgsub_enabled[bg]; + + const uint16 opt_valid_bit = (bg == BG1) ? 0x2000 : (bg == BG2) ? 0x4000 : 0x0000; + const uint8 bgpal_index = (mode == 0 ? (bg << 5) : 0); + + const uint8 pal_size = 2 << color_depth; //<<2 (*4), <<4 (*16), <<8 (*256) + const uint16 tile_mask = 0x0fff >> color_depth; //0x0fff, 0x07ff, 0x03ff + //4 + color_depth = >>(4-6) -- / {16, 32, 64 } bytes/tile + //index is a tile number count to add to base tile number + const unsigned tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth); + + const uint8 *bg_td = bg_tiledata[color_depth]; + const uint8 *bg_td_state = bg_tiledata_state[color_depth]; + + const uint8 tile_width = bg_info[bg].tw; + const uint8 tile_height = bg_info[bg].th; + const uint16 mask_x = bg_info[bg].mx; //screen width mask + const uint16 mask_y = bg_info[bg].my; //screen height mask + + uint16 y = regs.bg_y[bg]; + uint16 hscroll = regs.bg_hofs[bg]; + uint16 vscroll = regs.bg_vofs[bg]; + + const unsigned hires = (mode == 5 || mode == 6); + const unsigned width = (!hires ? 256 : 512); + + if(hires) { + hscroll <<= 1; + if(regs.interlace) y = (y << 1) + field(); + } + + uint16 hval, vval; + uint16 tile_pri, tile_num; + uint8 pal_index, pal_num; + uint16 hoffset, voffset, opt_x, col; + bool mirror_x, mirror_y; + + const uint8 *tile_ptr; + const uint16 *mtable = mosaic_table[regs.mosaic_enabled[bg] ? regs.mosaic_size : 0]; + const bool is_opt_mode = (mode == 2 || mode == 4 || mode == 6); + const bool is_direct_color_mode = (regs.direct_color == true && bg == BG1 && (mode == 3 || mode == 4)); + + build_window_tables(bg); + const uint8 *wt_main = window[bg].main; + const uint8 *wt_sub = window[bg].sub; + + uint16 prev_x = 0xffff, prev_y = 0xffff, prev_optx = 0xffff; + for(uint16 x = 0; x < width; x++) { + hoffset = mtable[x] + hscroll; + voffset = y + vscroll; + + if(is_opt_mode) { + opt_x = (x + (hscroll & 7)); + + //tile 0 is unaffected by OPT mode... + if(opt_x >= 8) { + //cache tile data in hval, vval if possible + if((opt_x >> 3) != (prev_optx >> 3)) { + prev_optx = opt_x; + + hval = bg_get_tile((opt_x - 8) + (regs.bg_hofs[BG3] & ~7), regs.bg_vofs[BG3]); + if(mode != 4) { + vval = bg_get_tile((opt_x - 8) + (regs.bg_hofs[BG3] & ~7), regs.bg_vofs[BG3] + 8); + } + } + + if(mode == 4) { + if(hval & opt_valid_bit) { + if(!(hval & 0x8000)) { + hoffset = opt_x + (hval & ~7); + } else { + voffset = y + hval; + } + } + } else { + if(hval & opt_valid_bit) { + hoffset = opt_x + (hval & ~7); + } + if(vval & opt_valid_bit) { + voffset = y + vval; + } + } + } + } + + hoffset &= mask_x; + voffset &= mask_y; + + if((hoffset >> 3) != prev_x || (voffset >> 3) != prev_y) { + prev_x = (hoffset >> 3); + prev_y = (voffset >> 3); + + tile_num = bg_get_tile(hoffset, voffset); //format = vhopppcc cccccccc + mirror_y = (tile_num & 0x8000); + mirror_x = (tile_num & 0x4000); + tile_pri = (tile_num & 0x2000) ? pri1_pos : pri0_pos; + pal_num = ((tile_num >> 10) & 7); + pal_index = bgpal_index + (pal_num << pal_size); + + if(tile_width == 4) { //16x16 horizontal tile mirroring + if((bool)(hoffset & 8) != mirror_x) tile_num++; + } + + if(tile_height == 4) { //16x16 vertical tile mirroring + if((bool)(voffset & 8) != mirror_y) tile_num += 16; + } + + tile_num &= 0x03ff; + tile_num += tiledata_index; + tile_num &= tile_mask; + + if(bg_td_state[tile_num] == 1) { + render_bg_tile(tile_num); + } + + if(mirror_y) voffset ^= 7; //invert y tile pos + tile_ptr = bg_td + (tile_num * 64) + ((voffset & 7) * 8); + } + + if(mirror_x) hoffset ^= 7; //invert x tile pos + col = *(tile_ptr + (hoffset & 7)); + if(col) { + if(is_direct_color_mode) { + col = get_direct_color(pal_num, col); + } else { + col = get_palette(col + pal_index); + } + + if(!hires) { + if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); } + if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); } + } else { + int hx = x >> 1; + if(x & 1) { + if(bg_enabled == true && !wt_main[hx]) { setpixel_main(hx); } + } else { + if(bgsub_enabled == true && !wt_sub[hx]) { setpixel_sub(hx); } + } + } + } + } +} + +#undef setpixel_main +#undef setpixel_sub + +#endif diff --git a/snes/alt/ppu-compatibility/render/cache.cpp b/snes/alt/ppu-compatibility/render/cache.cpp new file mode 100755 index 00000000..4e3b7be7 --- /dev/null +++ b/snes/alt/ppu-compatibility/render/cache.cpp @@ -0,0 +1,147 @@ +#ifdef PPU_CPP + +#define render_bg_tile_line_2bpp(mask) \ + col = !!(d0 & mask) << 0; \ + col += !!(d1 & mask) << 1; \ + *dest++ = col + +#define render_bg_tile_line_4bpp(mask) \ + col = !!(d0 & mask) << 0; \ + col += !!(d1 & mask) << 1; \ + col += !!(d2 & mask) << 2; \ + col += !!(d3 & mask) << 3; \ + *dest++ = col + +#define render_bg_tile_line_8bpp(mask) \ + col = !!(d0 & mask) << 0; \ + col += !!(d1 & mask) << 1; \ + col += !!(d2 & mask) << 2; \ + col += !!(d3 & mask) << 3; \ + col += !!(d4 & mask) << 4; \ + col += !!(d5 & mask) << 5; \ + col += !!(d6 & mask) << 6; \ + col += !!(d7 & mask) << 7; \ + *dest++ = col + +template +void PPU::render_bg_tile(uint16 tile_num) { + uint8 col, d0, d1, d2, d3, d4, d5, d6, d7; + + if(color_depth == COLORDEPTH_4) { + uint8 *dest = (uint8*)bg_tiledata[TILE_2BIT] + tile_num * 64; + unsigned pos = tile_num * 16; + unsigned y = 8; + while(y--) { + d0 = vram[pos ]; + d1 = vram[pos + 1]; + render_bg_tile_line_2bpp(0x80); + render_bg_tile_line_2bpp(0x40); + render_bg_tile_line_2bpp(0x20); + render_bg_tile_line_2bpp(0x10); + render_bg_tile_line_2bpp(0x08); + render_bg_tile_line_2bpp(0x04); + render_bg_tile_line_2bpp(0x02); + render_bg_tile_line_2bpp(0x01); + pos += 2; + } + bg_tiledata_state[TILE_2BIT][tile_num] = 0; + } + + if(color_depth == COLORDEPTH_16) { + uint8 *dest = (uint8*)bg_tiledata[TILE_4BIT] + tile_num * 64; + unsigned pos = tile_num * 32; + unsigned y = 8; + while(y--) { + d0 = vram[pos ]; + d1 = vram[pos + 1]; + d2 = vram[pos + 16]; + d3 = vram[pos + 17]; + render_bg_tile_line_4bpp(0x80); + render_bg_tile_line_4bpp(0x40); + render_bg_tile_line_4bpp(0x20); + render_bg_tile_line_4bpp(0x10); + render_bg_tile_line_4bpp(0x08); + render_bg_tile_line_4bpp(0x04); + render_bg_tile_line_4bpp(0x02); + render_bg_tile_line_4bpp(0x01); + pos += 2; + } + bg_tiledata_state[TILE_4BIT][tile_num] = 0; + } + + if(color_depth == COLORDEPTH_256) { + uint8 *dest = (uint8*)bg_tiledata[TILE_8BIT] + tile_num * 64; + unsigned pos = tile_num * 64; + unsigned y = 8; + while(y--) { + d0 = vram[pos ]; + d1 = vram[pos + 1]; + d2 = vram[pos + 16]; + d3 = vram[pos + 17]; + d4 = vram[pos + 32]; + d5 = vram[pos + 33]; + d6 = vram[pos + 48]; + d7 = vram[pos + 49]; + render_bg_tile_line_8bpp(0x80); + render_bg_tile_line_8bpp(0x40); + render_bg_tile_line_8bpp(0x20); + render_bg_tile_line_8bpp(0x10); + render_bg_tile_line_8bpp(0x08); + render_bg_tile_line_8bpp(0x04); + render_bg_tile_line_8bpp(0x02); + render_bg_tile_line_8bpp(0x01); + pos += 2; + } + bg_tiledata_state[TILE_8BIT][tile_num] = 0; + } +} + +#undef render_bg_tile_line_2bpp +#undef render_bg_tile_line_4bpp +#undef render_bg_tile_line_8bpp + +void PPU::flush_pixel_cache() { + uint16 main = get_palette(0); + uint16 sub = (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6) + ? main + : regs.color_rgb; + + unsigned i = 255; + do { + pixel_cache[i].src_main = main; + pixel_cache[i].src_sub = sub; + pixel_cache[i].bg_main = BACK; + pixel_cache[i].bg_sub = BACK; + pixel_cache[i].ce_main = false; + pixel_cache[i].ce_sub = false; + pixel_cache[i].pri_main = 0; + pixel_cache[i].pri_sub = 0; + } while(i--); +} + +void PPU::alloc_tiledata_cache() { + bg_tiledata[TILE_2BIT] = new uint8_t[262144](); + bg_tiledata[TILE_4BIT] = new uint8_t[131072](); + bg_tiledata[TILE_8BIT] = new uint8_t[ 65536](); + bg_tiledata_state[TILE_2BIT] = new uint8_t[ 4096](); + bg_tiledata_state[TILE_4BIT] = new uint8_t[ 2048](); + bg_tiledata_state[TILE_8BIT] = new uint8_t[ 1024](); +} + +//marks all tiledata cache entries as dirty +void PPU::flush_tiledata_cache() { + for(unsigned i = 0; i < 4096; i++) bg_tiledata_state[TILE_2BIT][i] = 1; + for(unsigned i = 0; i < 2048; i++) bg_tiledata_state[TILE_4BIT][i] = 1; + for(unsigned i = 0; i < 1024; i++) bg_tiledata_state[TILE_8BIT][i] = 1; +} + +void PPU::free_tiledata_cache() { + delete[] bg_tiledata[TILE_2BIT]; + delete[] bg_tiledata[TILE_4BIT]; + delete[] bg_tiledata[TILE_8BIT]; + delete[] bg_tiledata_state[TILE_2BIT]; + delete[] bg_tiledata_state[TILE_4BIT]; + delete[] bg_tiledata_state[TILE_8BIT]; +} + +#endif diff --git a/snes/alt/ppu-compatibility/render/line.cpp b/snes/alt/ppu-compatibility/render/line.cpp new file mode 100755 index 00000000..c7e870fe --- /dev/null +++ b/snes/alt/ppu-compatibility/render/line.cpp @@ -0,0 +1,118 @@ +#ifdef PPU_CPP + +inline uint16 PPU::get_palette(uint8 index) { + const unsigned addr = index << 1; + return cgram[addr] + (cgram[addr + 1] << 8); +} + +//p = 00000bgr +//t = BBGGGRRR +//r = 0BBb00GGGg0RRRr0 +inline uint16 PPU::get_direct_color(uint8 p, uint8 t) { + return ((t & 7) << 2) | ((p & 1) << 1) | + (((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) | + ((t >> 6) << 13) | ((p >> 2) << 12); +} + +inline uint16 PPU::get_pixel_normal(uint32 x) { + pixel_t &p = pixel_cache[x]; + uint16 src_main, src_sub; + uint8 bg_sub; + src_main = p.src_main; + + if(!regs.addsub_mode) { + bg_sub = BACK; + src_sub = regs.color_rgb; + } else { + bg_sub = p.bg_sub; + src_sub = p.src_sub; + } + + if(!window[COL].main[x]) { + if(!window[COL].sub[x]) { + return 0x0000; + } + src_main = 0x0000; + } + + if(!p.ce_main && regs.color_enabled[p.bg_main] && window[COL].sub[x]) { + bool halve = false; + if(regs.color_halve && window[COL].main[x]) { + if(regs.addsub_mode && bg_sub == BACK); + else { + halve = true; + } + } + return addsub(src_main, src_sub, halve); + } + + return src_main; +} + +inline uint16 PPU::get_pixel_swap(uint32 x) { + pixel_t &p = pixel_cache[x]; + uint16 src_main, src_sub; + uint8 bg_sub; + src_main = p.src_sub; + + if(!regs.addsub_mode) { + bg_sub = BACK; + src_sub = regs.color_rgb; + } else { + bg_sub = p.bg_main; + src_sub = p.src_main; + } + + if(!window[COL].main[x]) { + if(!window[COL].sub[x]) { + return 0x0000; + } + src_main = 0x0000; + } + + if(!p.ce_sub && regs.color_enabled[p.bg_sub] && window[COL].sub[x]) { + bool halve = false; + if(regs.color_halve && window[COL].main[x]) { + if(regs.addsub_mode && bg_sub == BACK); + else { + halve = true; + } + } + return addsub(src_main, src_sub, halve); + } + + return src_main; +} + +inline void PPU::render_line_output() { + uint32 *ptr = (uint32*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0); + uint32 curr, prev; + + if(!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) { + for(unsigned x = 0; x < 256; x++) { + curr = (regs.display_brightness << 15) | get_pixel_normal(x); + *ptr++ = curr; + } + } else { + for(unsigned x = 0, prev = 0; x < 256; x++) { + //blending is disabled below, as this should be done via video filtering + //blending code is left for reference purposes + + curr = (regs.display_brightness << 15) | get_pixel_swap(x); + *ptr++ = curr; //(prev + curr - ((prev ^ curr) & 0x0421)) >> 1; + //prev = curr; + + curr = (regs.display_brightness << 15) | get_pixel_normal(x); + *ptr++ = curr; //(prev + curr - ((prev ^ curr) & 0x0421)) >> 1; + //prev = curr; + } + } +} + +inline void PPU::render_line_clear() { + uint32 *ptr = (uint32*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0); + unsigned width = (!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) ? 256 : 512; + memset(ptr, 0, width * 2 * sizeof(uint32)); +} + +#endif diff --git a/snes/alt/ppu-compatibility/render/mode7.cpp b/snes/alt/ppu-compatibility/render/mode7.cpp new file mode 100755 index 00000000..747bafef --- /dev/null +++ b/snes/alt/ppu-compatibility/render/mode7.cpp @@ -0,0 +1,143 @@ +#ifdef PPU_CPP + +//bsnes mode7 renderer +// +//base algorithm written by anomie +//bsnes implementation written by byuu +// +//supports mode 7 + extbg + rotate + zoom + direct color + scrolling + m7sel + windowing + mosaic +//interlace and pseudo-hires support are automatic via main rendering routine + +//13-bit sign extend +//--s---vvvvvvvvvv -> ssssssvvvvvvvvvv +#define CLIP(x) ( ((x) & 0x2000) ? ( (x) | ~0x03ff) : ((x) & 0x03ff) ) + +template +void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) { + if(layer_enabled[bg][0] == false) pri0_pos = 0; + if(layer_enabled[bg][1] == false) pri1_pos = 0; + if(pri0_pos + pri1_pos == 0) return; + + if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return; + + int32 px, py; + int32 tx, ty, tile, palette; + + int32 a = sclip<16>(cache.m7a); + int32 b = sclip<16>(cache.m7b); + int32 c = sclip<16>(cache.m7c); + int32 d = sclip<16>(cache.m7d); + + int32 cx = sclip<13>(cache.m7x); + int32 cy = sclip<13>(cache.m7y); + int32 hofs = sclip<13>(cache.m7_hofs); + int32 vofs = sclip<13>(cache.m7_vofs); + + int _pri, _x; + bool _bg_enabled = regs.bg_enabled[bg]; + bool _bgsub_enabled = regs.bgsub_enabled[bg]; + + build_window_tables(bg); + uint8 *wt_main = window[bg].main; + uint8 *wt_sub = window[bg].sub; + + int32 y = (regs.mode7_vflip == false ? line : 255 - line); + + uint16 *mtable_x, *mtable_y; + if(bg == BG1) { + mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0]; + mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0]; + } else { //bg == BG2 + //Mode7 EXTBG BG2 uses BG1 mosaic enable to control vertical mosaic, + //and BG2 mosaic enable to control horizontal mosaic... + mtable_x = (uint16*)mosaic_table[(regs.mosaic_enabled[BG2] == true) ? regs.mosaic_size : 0]; + mtable_y = (uint16*)mosaic_table[(regs.mosaic_enabled[BG1] == true) ? regs.mosaic_size : 0]; + } + + int32 psx = ((a * CLIP(hofs - cx)) & ~63) + ((b * CLIP(vofs - cy)) & ~63) + ((b * mtable_y[y]) & ~63) + (cx << 8); + int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * CLIP(vofs - cy)) & ~63) + ((d * mtable_y[y]) & ~63) + (cy << 8); + for(int32 x = 0; x < 256; x++) { + px = psx + (a * mtable_x[x]); + py = psy + (c * mtable_x[x]); + + //mask floating-point bits (low 8 bits) + px >>= 8; + py >>= 8; + + switch(regs.mode7_repeat) { + case 0: //screen repetition outside of screen area + case 1: { //same as case 0 + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = vram[(ty * 128 + tx) << 1]; + palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + } break; + case 2: { //palette color 0 outside of screen area + if((px | py) & ~1023) { + palette = 0; + } else { + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = vram[(ty * 128 + tx) << 1]; + palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + } + } break; + case 3: { //character 0 repetition outside of screen area + if((px | py) & ~1023) { + tile = 0; + } else { + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = vram[(ty * 128 + tx) << 1]; + } + palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + } break; + } + + if(bg == BG1) { + _pri = pri0_pos; + } else { + _pri = (palette >> 7) ? pri1_pos : pri0_pos; + palette &= 0x7f; + } + + if(!palette) continue; + + _x = (regs.mode7_hflip == false) ? (x) : (255 - x); + + uint32 col; + if(regs.direct_color == true && bg == BG1) { + //direct color mode does not apply to bg2, as it is only 128 colors... + col = get_direct_color(0, palette); + } else { + col = get_palette(palette); + } + + if(regs.bg_enabled[bg] == true && !wt_main[_x]) { + if(pixel_cache[_x].pri_main < _pri) { + pixel_cache[_x].pri_main = _pri; + pixel_cache[_x].bg_main = bg; + pixel_cache[_x].src_main = col; + pixel_cache[_x].ce_main = false; + } + } + if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) { + if(pixel_cache[_x].pri_sub < _pri) { + pixel_cache[_x].pri_sub = _pri; + pixel_cache[_x].bg_sub = bg; + pixel_cache[_x].src_sub = col; + pixel_cache[_x].ce_sub = false; + } + } + } +} + +#undef CLIP + +#endif diff --git a/snes/alt/ppu-compatibility/render/oam.cpp b/snes/alt/ppu-compatibility/render/oam.cpp new file mode 100755 index 00000000..42544a02 --- /dev/null +++ b/snes/alt/ppu-compatibility/render/oam.cpp @@ -0,0 +1,237 @@ +#ifdef PPU_CPP + +void PPU::update_sprite_list(unsigned addr, uint8 data) { + if(addr < 0x0200) { + unsigned i = addr >> 2; + switch(addr & 3) { + case 0: sprite_list[i].x = (sprite_list[i].x & 0x0100) | data; break; + case 1: sprite_list[i].y = (data + 1) & 0xff; break; + case 2: sprite_list[i].character = data; break; + case 3: sprite_list[i].vflip = data & 0x80; + sprite_list[i].hflip = data & 0x40; + sprite_list[i].priority = (data >> 4) & 3; + sprite_list[i].palette = (data >> 1) & 7; + sprite_list[i].use_nameselect = data & 0x01; + } + } else { + unsigned i = (addr & 0x1f) << 2; + sprite_list[i + 0].x = ((data & 0x01) << 8) | (sprite_list[i + 0].x & 0xff); + sprite_list[i + 0].size = data & 0x02; + sprite_list[i + 1].x = ((data & 0x04) << 6) | (sprite_list[i + 1].x & 0xff); + sprite_list[i + 1].size = data & 0x08; + sprite_list[i + 2].x = ((data & 0x10) << 4) | (sprite_list[i + 2].x & 0xff); + sprite_list[i + 2].size = data & 0x20; + sprite_list[i + 3].x = ((data & 0x40) << 2) | (sprite_list[i + 3].x & 0xff); + sprite_list[i + 3].size = data & 0x80; + } +} + +void PPU::build_sprite_list() { + if(sprite_list_valid == true) return; + sprite_list_valid = true; + + for(unsigned i = 0; i < 128; i++) { + const bool size = sprite_list[i].size; + + switch(cache.oam_basesize) { + case 0: sprite_list[i].width = (!size) ? 8 : 16; + sprite_list[i].height = (!size) ? 8 : 16; + break; + case 1: sprite_list[i].width = (!size) ? 8 : 32; + sprite_list[i].height = (!size) ? 8 : 32; + break; + case 2: sprite_list[i].width = (!size) ? 8 : 64; + sprite_list[i].height = (!size) ? 8 : 64; + break; + case 3: sprite_list[i].width = (!size) ? 16 : 32; + sprite_list[i].height = (!size) ? 16 : 32; + break; + case 4: sprite_list[i].width = (!size) ? 16 : 64; + sprite_list[i].height = (!size) ? 16 : 64; + break; + case 5: sprite_list[i].width = (!size) ? 32 : 64; + sprite_list[i].height = (!size) ? 32 : 64; + break; + case 6: sprite_list[i].width = (!size) ? 16 : 32; + sprite_list[i].height = (!size) ? 32 : 64; + if(regs.oam_interlace && !size) sprite_list[i].height = 16; + //32x64 height is not affected by oam_interlace setting + break; + case 7: sprite_list[i].width = (!size) ? 16 : 32; + sprite_list[i].height = (!size) ? 32 : 32; + if(regs.oam_interlace && !size) sprite_list[i].height = 16; + break; + } + } +} + +bool PPU::is_sprite_on_scanline() { + //if sprite is entirely offscreen and doesn't wrap around to the left side of the screen, + //then it is not counted. this *should* be 256, and not 255, even though dot 256 is offscreen. + sprite_item *spr = &sprite_list[active_sprite]; + if(spr->x > 256 && (spr->x + spr->width - 1) < 512) return false; + + int spr_height = (regs.oam_interlace == false) ? (spr->height) : (spr->height >> 1); + if(line >= spr->y && line < (spr->y + spr_height)) return true; + if((spr->y + spr_height) >= 256 && line < ((spr->y + spr_height) & 255)) return true; + return false; +} + +void PPU::load_oam_tiles() { + sprite_item *spr = &sprite_list[active_sprite]; + uint16 tile_width = spr->width >> 3; + int x = spr->x; + int y = (line - spr->y) & 0xff; + if(regs.oam_interlace == true) { + y <<= 1; + } + + if(spr->vflip == true) { + if(spr->width == spr->height) { + y = (spr->height - 1) - y; + } else { + y = (y < spr->width) ? ((spr->width - 1) - y) : (spr->width + ((spr->width - 1) - (y - spr->width))); + } + } + + if(regs.oam_interlace == true) { + y = (spr->vflip == false) ? (y + field()) : (y - field()); + } + + x &= 511; + y &= 255; + + uint16 tdaddr = cache.oam_tdaddr; + uint16 chrx = (spr->character ) & 15; + uint16 chry = (spr->character >> 4) & 15; + if(spr->use_nameselect == true) { + tdaddr += (256 * 32) + (cache.oam_nameselect << 13); + } + chry += (y >> 3); + chry &= 15; + chry <<= 4; + + for(unsigned tx = 0; tx < tile_width; tx++) { + unsigned sx = (x + (tx << 3)) & 511; + //ignore sprites that are offscreen, x==256 is a special case that loads all tiles in OBJ + if(x != 256 && sx >= 256 && (sx + 7) < 512) continue; + + if(regs.oam_tilecount++ >= 34) break; + unsigned n = regs.oam_tilecount - 1; + oam_tilelist[n].x = sx; + oam_tilelist[n].y = y; + oam_tilelist[n].pri = spr->priority; + oam_tilelist[n].pal = 128 + (spr->palette << 4); + oam_tilelist[n].hflip = spr->hflip; + + unsigned mx = (spr->hflip == false) ? tx : ((tile_width - 1) - tx); + unsigned pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5); + oam_tilelist[n].tile = (pos >> 5) & 0x07ff; + } +} + +void PPU::render_oam_tile(int tile_num) { + oam_tileitem *t = &oam_tilelist[tile_num]; + uint8 *oam_td = (uint8*)bg_tiledata[COLORDEPTH_16]; + uint8 *oam_td_state = (uint8*)bg_tiledata_state[COLORDEPTH_16]; + + if(oam_td_state[t->tile] == 1) { + render_bg_tile(t->tile); + } + + unsigned sx = t->x; + uint8 *tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3); + for(unsigned x = 0; x < 8; x++) { + sx &= 511; + if(sx < 256) { + unsigned col = *(tile_ptr + ((t->hflip == false) ? x : (7 - x))); + if(col) { + col += t->pal; + oam_line_pal[sx] = col; + oam_line_pri[sx] = t->pri; + } + } + sx++; + } +} + +void PPU::render_line_oam_rto() { + build_sprite_list(); + + regs.oam_itemcount = 0; + regs.oam_tilecount = 0; + memset(oam_line_pri, OAM_PRI_NONE, 256); + memset(oam_itemlist, 0xff, 32); + for(int s = 0; s < 34; s++) oam_tilelist[s].tile = 0xffff; + + for(int s = 0; s < 128; s++) { + active_sprite = (s + regs.oam_firstsprite) & 127; + if(is_sprite_on_scanline() == false) continue; + if(regs.oam_itemcount++ >= 32) break; + oam_itemlist[regs.oam_itemcount - 1] = (s + regs.oam_firstsprite) & 127; + } + + if(regs.oam_itemcount > 0 && oam_itemlist[regs.oam_itemcount - 1] != 0xff) { + regs.ioamaddr = 0x0200 + (oam_itemlist[regs.oam_itemcount - 1] >> 2); + } + + for(int s = 31; s >= 0; s--) { + if(oam_itemlist[s] == 0xff) continue; + active_sprite = oam_itemlist[s]; + load_oam_tiles(); + } + + regs.time_over |= (regs.oam_tilecount > 34); + regs.range_over |= (regs.oam_itemcount > 32); +} + +#define setpixel_main(x) \ + if(pixel_cache[x].pri_main < pri) { \ + pixel_cache[x].pri_main = pri; \ + pixel_cache[x].bg_main = OAM; \ + pixel_cache[x].src_main = get_palette(oam_line_pal[x]); \ + pixel_cache[x].ce_main = (oam_line_pal[x] < 192); \ + } +#define setpixel_sub(x) \ + if(pixel_cache[x].pri_sub < pri) { \ + pixel_cache[x].pri_sub = pri; \ + pixel_cache[x].bg_sub = OAM; \ + pixel_cache[x].src_sub = get_palette(oam_line_pal[x]); \ + pixel_cache[x].ce_sub = (oam_line_pal[x] < 192); \ + } + +void PPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) { + if(layer_enabled[OAM][0] == false) pri0_pos = 0; + if(layer_enabled[OAM][1] == false) pri1_pos = 0; + if(layer_enabled[OAM][2] == false) pri2_pos = 0; + if(layer_enabled[OAM][3] == false) pri3_pos = 0; + if(pri0_pos + pri1_pos + pri2_pos + pri3_pos == 0) return; + + if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false) return; + + for(unsigned s = 0; s < 34; s++) { + if(oam_tilelist[s].tile == 0xffff) continue; + render_oam_tile(s); + } + + bool bg_enabled = regs.bg_enabled[OAM]; + bool bgsub_enabled = regs.bgsub_enabled[OAM]; + + build_window_tables(OAM); + uint8 *wt_main = window[OAM].main; + uint8 *wt_sub = window[OAM].sub; + + unsigned pri_tbl[4] = { pri0_pos, pri1_pos, pri2_pos, pri3_pos }; + for(int x = 0; x < 256; x++) { + if(oam_line_pri[x] == OAM_PRI_NONE) continue; + + unsigned pri = pri_tbl[oam_line_pri[x]]; + if(bg_enabled == true && !wt_main[x]) { setpixel_main(x); } + if(bgsub_enabled == true && !wt_sub[x]) { setpixel_sub(x); } + } +} + +#undef setpixel_main +#undef setpixel_sub + +#endif diff --git a/snes/alt/ppu-compatibility/render/render.cpp b/snes/alt/ppu-compatibility/render/render.cpp new file mode 100755 index 00000000..c185fa0a --- /dev/null +++ b/snes/alt/ppu-compatibility/render/render.cpp @@ -0,0 +1,129 @@ +#ifdef PPU_CPP + +#include "cache.cpp" +#include "windows.cpp" +#include "bg.cpp" +#include "oam.cpp" +#include "mode7.cpp" +#include "addsub.cpp" +#include "line.cpp" + +//Mode 0: -> +// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 +// BG4B, BG3B, OAM0, BG4A, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3 +void PPU::render_line_mode0() { + render_line_bg<0, BG1, COLORDEPTH_4>(8, 11); + render_line_bg<0, BG2, COLORDEPTH_4>(7, 10); + render_line_bg<0, BG3, COLORDEPTH_4>(2, 5); + render_line_bg<0, BG4, COLORDEPTH_4>(1, 4); + render_line_oam(3, 6, 9, 12); +} + +//Mode 1 (pri=1): -> +// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 +// BG3B, OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3, BG3A +// +//Mode 1 (pri=0): -> +// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 +// BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3 +void PPU::render_line_mode1() { + if(regs.bg3_priority) { + render_line_bg<1, BG1, COLORDEPTH_16>(5, 8); + render_line_bg<1, BG2, COLORDEPTH_16>(4, 7); + render_line_bg<1, BG3, COLORDEPTH_4 >(1, 10); + render_line_oam(2, 3, 6, 9); + } else { + render_line_bg<1, BG1, COLORDEPTH_16>(6, 9); + render_line_bg<1, BG2, COLORDEPTH_16>(5, 8); + render_line_bg<1, BG3, COLORDEPTH_4 >(1, 3); + render_line_oam(2, 4, 7, 10); + } +} + +//Mode 2: -> +// 1, 2, 3, 4, 5, 6, 7, 8 +// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3 +void PPU::render_line_mode2() { + render_line_bg<2, BG1, COLORDEPTH_16>(3, 7); + render_line_bg<2, BG2, COLORDEPTH_16>(1, 5); + render_line_oam(2, 4, 6, 8); +} + +//Mode 3: -> +// 1, 2, 3, 4, 5, 6, 7, 8 +// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3 +void PPU::render_line_mode3() { + render_line_bg<3, BG1, COLORDEPTH_256>(3, 7); + render_line_bg<3, BG2, COLORDEPTH_16 >(1, 5); + render_line_oam(2, 4, 6, 8); +} + +//Mode 4: -> +// 1, 2, 3, 4, 5, 6, 7, 8 +// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3 +void PPU::render_line_mode4() { + render_line_bg<4, BG1, COLORDEPTH_256>(3, 7); + render_line_bg<4, BG2, COLORDEPTH_4 >(1, 5); + render_line_oam(2, 4, 6, 8); +} + +//Mode 5: -> +// 1, 2, 3, 4, 5, 6, 7, 8 +// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3 +void PPU::render_line_mode5() { + render_line_bg<5, BG1, COLORDEPTH_16>(3, 7); + render_line_bg<5, BG2, COLORDEPTH_4 >(1, 5); + render_line_oam(2, 4, 6, 8); +} + +//Mode 6: -> +// 1, 2, 3, 4, 5, 6 +// OAM0, BG1B, OAM1, OAM2, BG1A, OAM3 +void PPU::render_line_mode6() { + render_line_bg<6, BG1, COLORDEPTH_16>(2, 5); + render_line_oam(1, 3, 4, 6); +} + +//Mode7: -> +// 1, 2, 3, 4, 5 +// OAM0, BG1n, OAM1, OAM2, OAM3 + +//Mode 7 EXTBG: -> +// 1, 2, 3, 4, 5, 6, 7 +// BG2B, OAM0, BG1n, OAM1, BG2A, OAM2, OAM3 +void PPU::render_line_mode7() { + if(regs.mode7_extbg == false) { + render_line_mode7(2, 2); + render_line_oam(1, 3, 4, 5); + } else { + render_line_mode7(3, 3); + render_line_mode7(1, 5); + render_line_oam(2, 4, 6, 7); + } +} + +void PPU::render_line() { + if(regs.display_disabled == true) { + render_line_clear(); + return; + } + + flush_pixel_cache(); + build_window_tables(COL); + update_bg_info(); + + switch(regs.bg_mode) { + case 0: render_line_mode0(); break; + case 1: render_line_mode1(); break; + case 2: render_line_mode2(); break; + case 3: render_line_mode3(); break; + case 4: render_line_mode4(); break; + case 5: render_line_mode5(); break; + case 6: render_line_mode6(); break; + case 7: render_line_mode7(); break; + } + + render_line_output(); +} + +#endif diff --git a/snes/alt/ppu-compatibility/render/render.hpp b/snes/alt/ppu-compatibility/render/render.hpp new file mode 100755 index 00000000..91438009 --- /dev/null +++ b/snes/alt/ppu-compatibility/render/render.hpp @@ -0,0 +1,99 @@ +//render.cpp +inline void render_line_mode0(); +inline void render_line_mode1(); +inline void render_line_mode2(); +inline void render_line_mode3(); +inline void render_line_mode4(); +inline void render_line_mode5(); +inline void render_line_mode6(); +inline void render_line_mode7(); + +//cache.cpp +enum { COLORDEPTH_4 = 0, COLORDEPTH_16 = 1, COLORDEPTH_256 = 2 }; +enum { TILE_2BIT = 0, TILE_4BIT = 1, TILE_8BIT = 2 }; + +struct pixel_t { + //bgr555 color data for main/subscreen pixels: 0x0000 = transparent / use palette color # 0 + //needs to be bgr555 instead of palette index for direct color mode ($2130 bit 0) to work + uint16 src_main, src_sub; + //indicates source of palette # for main/subscreen (BG1-4, OAM, or back) + uint8 bg_main, bg_sub; + //color_exemption -- true when bg == OAM && palette index >= 192, disables color add/sub effects + uint8 ce_main, ce_sub; + //priority level of src_n. to set src_n, + //the priority of the pixel must be >pri_n + uint8 pri_main, pri_sub; +} pixel_cache[256]; + +uint8 *bg_tiledata[3]; +uint8 *bg_tiledata_state[3]; //0 = valid, 1 = dirty + +template void render_bg_tile(uint16 tile_num); +inline void flush_pixel_cache(); +void alloc_tiledata_cache(); +void flush_tiledata_cache(); +void free_tiledata_cache(); + +//windows.cpp +struct window_t { + uint8 main[256], sub[256]; +} window[6]; + +void build_window_table(uint8 bg, bool mainscreen); +void build_window_tables(uint8 bg); + +//bg.cpp +struct { + uint16 tw, th; //tile width, height + uint16 mx, my; //screen mask x, y + uint16 scx, scy; //sc index offsets +} bg_info[4]; +void update_bg_info(); + +template uint16 bg_get_tile(uint16 x, uint16 y); +template void render_line_bg(uint8 pri0_pos, uint8 pri1_pos); + +//oam.cpp +struct sprite_item { + uint8 width, height; + uint16 x, y; + uint8 character; + bool use_nameselect; + bool vflip, hflip; + uint8 palette; + uint8 priority; + bool size; +} sprite_list[128]; +bool sprite_list_valid; +unsigned active_sprite; + +uint8 oam_itemlist[32]; +struct oam_tileitem { + uint16 x, y, pri, pal, tile; + bool hflip; +} oam_tilelist[34]; + +enum { OAM_PRI_NONE = 4 }; +uint8 oam_line_pal[256], oam_line_pri[256]; + +void update_sprite_list(unsigned addr, uint8 data); +void build_sprite_list(); +bool is_sprite_on_scanline(); +void load_oam_tiles(); +void render_oam_tile(int tile_num); +void render_line_oam_rto(); +void render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos); + +//mode7.cpp +template void render_line_mode7(uint8 pri0_pos, uint8 pri1_pos); + +//addsub.cpp +inline uint16 addsub(uint32 x, uint32 y, bool halve); + +//line.cpp +inline uint16 get_palette(uint8 index); +inline uint16 get_direct_color(uint8 p, uint8 t); +inline uint16 get_pixel_normal(uint32 x); +inline uint16 get_pixel_swap(uint32 x); +void render_line_output(); +void render_line_clear(); diff --git a/snes/alt/ppu-compatibility/render/windows.cpp b/snes/alt/ppu-compatibility/render/windows.cpp new file mode 100755 index 00000000..d8b4fd1a --- /dev/null +++ b/snes/alt/ppu-compatibility/render/windows.cpp @@ -0,0 +1,70 @@ +#ifdef PPU_CPP + +//screen: 0 = main, 1 = sub +void PPU::build_window_table(uint8 bg, bool screen) { + bool set = 1, clr = 0; + uint8 *table = (screen == 0 ? window[bg].main : window[bg].sub); + + if(bg != COL) { + if(screen == 0 && regs.window_enabled[bg] == false) { + memset(table, 0, 256); + return; + } + if(screen == 1 && regs.sub_window_enabled[bg] == false) { + memset(table, 0, 256); + return; + } + } else { + switch(screen == 0 ? regs.color_mask : regs.colorsub_mask) { + case 0: memset(table, 1, 256); return; //always + case 3: memset(table, 0, 256); return; //never + case 1: set = 1, clr = 0; break; //inside window only + case 2: set = 0, clr = 1; break; //outside window only + } + } + + const uint16 window1_left = regs.window1_left; + const uint16 window1_right = regs.window1_right; + const uint16 window2_left = regs.window2_left; + const uint16 window2_right = regs.window2_right; + + if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == false) { + memset(table, clr, 256); + return; + } + + if(regs.window1_enabled[bg] == true && regs.window2_enabled[bg] == false) { + if(regs.window1_invert[bg] == true) set ^= clr ^= set ^= clr; + for(unsigned x = 0; x < 256; x++) { + table[x] = (x >= window1_left && x <= window1_right) ? set : clr; + } + return; + } + + if(regs.window1_enabled[bg] == false && regs.window2_enabled[bg] == true) { + if(regs.window2_invert[bg] == true) set ^= clr ^= set ^= clr; + for(unsigned x = 0; x < 256; x++) { + table[x] = (x >= window2_left && x <= window2_right) ? set : clr; + } + return; + } + + for(unsigned x = 0; x < 256; x++) { + bool w1_mask = (x >= window1_left && x <= window1_right) ^ regs.window1_invert[bg]; + bool w2_mask = (x >= window2_left && x <= window2_right) ^ regs.window2_invert[bg]; + + switch(regs.window_mask[bg]) { + case 0: table[x] = (w1_mask | w2_mask) == 1 ? set : clr; break; //or + case 1: table[x] = (w1_mask & w2_mask) == 1 ? set : clr; break; //and + case 2: table[x] = (w1_mask ^ w2_mask) == 1 ? set : clr; break; //xor + case 3: table[x] = (w1_mask ^ w2_mask) == 0 ? set : clr; break; //xnor + } + } +} + +void PPU::build_window_tables(uint8 bg) { + build_window_table(bg, 0); + build_window_table(bg, 1); +} + +#endif diff --git a/snes/alt/ppu-compatibility/serialization.cpp b/snes/alt/ppu-compatibility/serialization.cpp new file mode 100755 index 00000000..d2711e4a --- /dev/null +++ b/snes/alt/ppu-compatibility/serialization.cpp @@ -0,0 +1,207 @@ +#ifdef PPU_CPP + +void PPUcounter::serialize(serializer &s) { + s.integer(status.interlace); + s.integer(status.field); + s.integer(status.vcounter); + s.integer(status.hcounter); + + s.array(history.field); + s.array(history.vcounter); + s.array(history.hcounter); + s.integer(history.index); +} + +void PPU::serialize(serializer &s) { + Processor::serialize(s); + PPUcounter::serialize(s); + + s.array(vram); + s.array(oam); + s.array(cgram); + + s.integer(ppu1_version); + s.integer(ppu2_version); + + s.integer(region); + s.integer(line); + + s.integer(display.interlace); + s.integer(display.overscan); + + s.integer(cache.oam_basesize); + s.integer(cache.oam_nameselect); + s.integer(cache.oam_tdaddr); + + s.integer(regs.ppu1_mdr); + s.integer(regs.ppu2_mdr); + for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_y[n]); + + s.integer(regs.ioamaddr); + s.integer(regs.icgramaddr); + + s.integer(regs.display_disabled); + s.integer(regs.display_brightness); + + s.integer(regs.oam_basesize); + s.integer(regs.oam_nameselect); + s.integer(regs.oam_tdaddr); + + s.integer(regs.oam_baseaddr); + s.integer(regs.oam_addr); + s.integer(regs.oam_priority); + s.integer(regs.oam_firstsprite); + + s.integer(regs.oam_latchdata); + + for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tilesize[n]); + s.integer(regs.bg3_priority); + s.integer(regs.bg_mode); + + s.integer(regs.mosaic_size); + for(unsigned n = 0; n < 4; n++) s.integer(regs.mosaic_enabled[n]); + s.integer(regs.mosaic_countdown); + + for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_scaddr[n]); + for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_scsize[n]); + + for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tdaddr[n]); + + s.integer(regs.bg_ofslatch); + s.integer(regs.m7_hofs); + s.integer(regs.m7_vofs); + for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_hofs[n]); + for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_vofs[n]); + + s.integer(regs.vram_incmode); + s.integer(regs.vram_mapping); + s.integer(regs.vram_incsize); + + s.integer(regs.vram_addr); + + s.integer(regs.mode7_repeat); + s.integer(regs.mode7_vflip); + s.integer(regs.mode7_hflip); + + s.integer(regs.m7_latch); + s.integer(regs.m7a); + s.integer(regs.m7b); + s.integer(regs.m7c); + s.integer(regs.m7d); + s.integer(regs.m7x); + s.integer(regs.m7y); + + s.integer(regs.cgram_addr); + + s.integer(regs.cgram_latchdata); + + for(unsigned n = 0; n < 6; n++) s.integer(regs.window1_enabled[n]); + for(unsigned n = 0; n < 6; n++) s.integer(regs.window1_invert [n]); + for(unsigned n = 0; n < 6; n++) s.integer(regs.window2_enabled[n]); + for(unsigned n = 0; n < 6; n++) s.integer(regs.window2_invert [n]); + + s.integer(regs.window1_left); + s.integer(regs.window1_right); + s.integer(regs.window2_left); + s.integer(regs.window2_right); + + for(unsigned n = 0; n < 6; n++) s.integer(regs.window_mask[n]); + for(unsigned n = 0; n < 5; n++) s.integer(regs.bg_enabled[n]); + for(unsigned n = 0; n < 5; n++) s.integer(regs.bgsub_enabled[n]); + for(unsigned n = 0; n < 5; n++) s.integer(regs.window_enabled[n]); + for(unsigned n = 0; n < 5; n++) s.integer(regs.sub_window_enabled[n]); + + s.integer(regs.color_mask); + s.integer(regs.colorsub_mask); + s.integer(regs.addsub_mode); + s.integer(regs.direct_color); + + s.integer(regs.color_mode); + s.integer(regs.color_halve); + for(unsigned n = 0; n < 6; n++) s.integer(regs.color_enabled[n]); + + s.integer(regs.color_r); + s.integer(regs.color_g); + s.integer(regs.color_b); + s.integer(regs.color_rgb); + + s.integer(regs.mode7_extbg); + s.integer(regs.pseudo_hires); + s.integer(regs.overscan); + s.integer(regs.scanlines); + s.integer(regs.oam_interlace); + s.integer(regs.interlace); + + s.integer(regs.hcounter); + s.integer(regs.vcounter); + s.integer(regs.latch_hcounter); + s.integer(regs.latch_vcounter); + s.integer(regs.counters_latched); + + s.integer(regs.vram_readbuffer); + + s.integer(regs.time_over); + s.integer(regs.range_over); + s.integer(regs.oam_itemcount); + s.integer(regs.oam_tilecount); + + for(unsigned n = 0; n < 256; n++) { + s.integer(pixel_cache[n].src_main); + s.integer(pixel_cache[n].src_sub); + s.integer(pixel_cache[n].bg_main); + s.integer(pixel_cache[n].bg_sub); + s.integer(pixel_cache[n].ce_main); + s.integer(pixel_cache[n].ce_sub); + s.integer(pixel_cache[n].pri_main); + s.integer(pixel_cache[n].pri_sub); + } + + //better to just take a small speed hit than store all of bg_tiledata[3][] ... + flush_tiledata_cache(); + + for(unsigned n = 0; n < 6; n++) { + s.array(window[n].main, 256); + s.array(window[n].sub, 256); + } + + for(unsigned n = 0; n < 4; n++) { + s.integer(bg_info[n].tw); + s.integer(bg_info[n].th); + s.integer(bg_info[n].mx); + s.integer(bg_info[n].my); + s.integer(bg_info[n].scx); + s.integer(bg_info[n].scy); + } + + for(unsigned n = 0; n < 128; n++) { + s.integer(sprite_list[n].width); + s.integer(sprite_list[n].height); + s.integer(sprite_list[n].x); + s.integer(sprite_list[n].y); + s.integer(sprite_list[n].character); + s.integer(sprite_list[n].use_nameselect); + s.integer(sprite_list[n].vflip); + s.integer(sprite_list[n].hflip); + s.integer(sprite_list[n].palette); + s.integer(sprite_list[n].priority); + s.integer(sprite_list[n].size); + } + s.integer(sprite_list_valid); + s.integer(active_sprite); + + s.array(oam_itemlist, 32); + + for(unsigned n = 0; n < 34; n++) { + s.integer(oam_tilelist[n].x); + s.integer(oam_tilelist[n].y); + s.integer(oam_tilelist[n].pri); + s.integer(oam_tilelist[n].pal); + s.integer(oam_tilelist[n].tile); + s.integer(oam_tilelist[n].hflip); + } + + s.array(oam_line_pal, 256); + s.array(oam_line_pri, 256); +} + +#endif diff --git a/snes/alt/ppu-performance/background/background.cpp b/snes/alt/ppu-performance/background/background.cpp new file mode 100755 index 00000000..29c70aaf --- /dev/null +++ b/snes/alt/ppu-performance/background/background.cpp @@ -0,0 +1,184 @@ +#ifdef PPU_CPP + +#include "mode7.cpp" + +unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) { + unsigned tile_x = (hoffset & mask_x) >> tile_width; + unsigned tile_y = (voffset & mask_y) >> tile_height; + + unsigned tile_pos = ((tile_y & 0x1f) << 5) + (tile_x & 0x1f); + if(tile_y & 0x20) tile_pos += scy; + if(tile_x & 0x20) tile_pos += scx; + + const uint16 tiledata_addr = regs.screen_addr + (tile_pos << 1); + return (ppu.vram[tiledata_addr + 0] << 0) + (ppu.vram[tiledata_addr + 1] << 8); +} + +void PPU::Background::offset_per_tile(unsigned x, unsigned y, unsigned &hoffset, unsigned &voffset) { + unsigned opt_x = (x + (hscroll & 7)), hval, vval; + if(opt_x >= 8) { + hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0); + if(self.regs.bgmode != 4) + vval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8); + + if(self.regs.bgmode == 4) { + if(hval & opt_valid_bit) { + if(!(hval & 0x8000)) { + hoffset = opt_x + (hval & ~7); + } else { + voffset = y + hval; + } + } + } else { + if(hval & opt_valid_bit) { + hoffset = opt_x + (hval & ~7); + } + if(vval & opt_valid_bit) { + voffset = y + vval; + } + } + } +} + +void PPU::Background::scanline() { + if(self.vcounter() == 1) { + mosaic_vcounter = regs.mosaic + 1; + mosaic_voffset = 1; + } else if(--mosaic_vcounter == 0) { + mosaic_vcounter = regs.mosaic + 1; + mosaic_voffset += regs.mosaic + 1; + } + if(self.regs.display_disable) return; + + hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); + width = !hires ? 256 : 512; + + tile_height = regs.tile_size ? 4 : 3; + tile_width = hires ? 4 : tile_height; + + mask_x = (tile_height == 4 ? width << 1 : width); + mask_y = mask_x; + if(regs.screen_size & 1) mask_x <<= 1; + if(regs.screen_size & 2) mask_y <<= 1; + mask_x--; + mask_y--; + + scx = (regs.screen_size & 1 ? 32 << 5 : 0); + scy = (regs.screen_size & 2 ? 32 << 5 : 0); + if(regs.screen_size == 3) scy <<= 1; +} + +void PPU::Background::render() { + if(regs.mode == Mode::Inactive) return; + if(regs.main_enable == false && regs.sub_enable == false) return; + + if(regs.main_enable) window.render(0); + if(regs.sub_enable) window.render(1); + if(regs.mode == Mode::Mode7) return render_mode7(); + + unsigned priority0 = (priority0_enable ? regs.priority0 : 0); + unsigned priority1 = (priority1_enable ? regs.priority1 : 0); + if(priority0 + priority1 == 0) return; + + unsigned mosaic_hcounter = 1; + unsigned mosaic_palette = 0; + unsigned mosaic_priority = 0; + unsigned mosaic_color = 0; + + const unsigned bgpal_index = (self.regs.bgmode == 0 ? id << 5 : 0); + const unsigned pal_size = 2 << regs.mode; + const unsigned tile_mask = 0x0fff >> regs.mode; + const unsigned tiledata_index = regs.tiledata_addr >> (4 + regs.mode); + + hscroll = regs.hoffset; + vscroll = regs.voffset; + + unsigned y = (regs.mosaic == 0 ? self.vcounter() : mosaic_voffset); + if(hires) { + hscroll <<= 1; + if(self.regs.interlace) y = (y << 1) + self.field(); + } + + unsigned tile_pri, tile_num; + unsigned pal_index, pal_num; + unsigned hoffset, voffset, col; + bool mirror_x, mirror_y; + + const bool is_opt_mode = (self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6); + const bool is_direct_color_mode = (self.screen.regs.direct_color == true && id == ID::BG1 && (self.regs.bgmode == 3 || self.regs.bgmode == 4)); + + signed x = 0 - (hscroll & 7); + while(x < width) { + hoffset = x + hscroll; + voffset = y + vscroll; + if(is_opt_mode) offset_per_tile(x, y, hoffset, voffset); + hoffset &= mask_x; + voffset &= mask_y; + + tile_num = get_tile(hoffset, voffset); + mirror_y = tile_num & 0x8000; + mirror_x = tile_num & 0x4000; + tile_pri = tile_num & 0x2000 ? priority1 : priority0; + pal_num = (tile_num >> 10) & 7; + pal_index = (bgpal_index + (pal_num << pal_size)) & 0xff; + + if(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile_num += 1; + if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile_num += 16; + tile_num = ((tile_num & 0x03ff) + tiledata_index) & tile_mask; + + if(mirror_y) voffset ^= 7; + unsigned mirror_xmask = !mirror_x ? 0 : 7; + + uint8 *tiledata = self.cache.tile(regs.mode, tile_num); + tiledata += ((voffset & 7) * 8); + + for(unsigned n = 0; n < 8; n++, x++) { + if(x & width) continue; + if(--mosaic_hcounter == 0) { + mosaic_hcounter = regs.mosaic + 1; + mosaic_palette = tiledata[n ^ mirror_xmask]; + mosaic_priority = tile_pri; + if(is_direct_color_mode) { + mosaic_color = self.screen.get_direct_color(pal_num, mosaic_palette); + } else { + mosaic_color = self.screen.get_palette(pal_index + mosaic_palette); + } + } + if(mosaic_palette == 0) continue; + + if(hires == false) { + if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, mosaic_color, mosaic_priority, id); + if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, mosaic_color, mosaic_priority, id); + } else { + signed half_x = x >> 1; + if(x & 1) { + if(regs.main_enable && !window.main[half_x]) self.screen.output.plot_main(half_x, mosaic_color, mosaic_priority, id); + } else { + if(regs.sub_enable && !window.sub[half_x]) self.screen.output.plot_sub(half_x, mosaic_color, mosaic_priority, id); + } + } + } + } +} + +PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) { + priority0_enable = true; + priority1_enable = true; + + opt_valid_bit = (id == ID::BG1 ? 0x2000 : id == ID::BG2 ? 0x4000 : 0x0000); + + mosaic_table = new uint16*[16]; + for(unsigned m = 0; m < 16; m++) { + mosaic_table[m] = new uint16[4096]; + for(unsigned x = 0; x < 4096; x++) { + mosaic_table[m][x] = (x / (m + 1)) * (m + 1); + } + } +} + +PPU::Background::~Background() { + for(unsigned m = 0; m < 16; m++) delete[] mosaic_table[m]; + delete[] mosaic_table; +} + +#endif diff --git a/snes/alt/ppu-performance/background/background.hpp b/snes/alt/ppu-performance/background/background.hpp new file mode 100755 index 00000000..04facf00 --- /dev/null +++ b/snes/alt/ppu-performance/background/background.hpp @@ -0,0 +1,66 @@ +class Background { + struct ID { enum { BG1, BG2, BG3, BG4 }; }; + struct Mode { enum { BPP2, BPP4, BPP8, Mode7, Inactive }; }; + struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; }; + struct TileSize { enum { Size8x8, Size16x16 }; }; + + bool priority0_enable; + bool priority1_enable; + + struct Regs { + unsigned mode; + unsigned priority0; + unsigned priority1; + + bool tile_size; + unsigned mosaic; + + unsigned screen_addr; + unsigned screen_size; + unsigned tiledata_addr; + + unsigned hoffset; + unsigned voffset; + + bool main_enable; + bool sub_enable; + } regs; + + uint16 **mosaic_table; + + const unsigned id; + unsigned opt_valid_bit; + + bool hires; + signed width; + + unsigned tile_width; + unsigned tile_height; + + unsigned mask_x; + unsigned mask_y; + + unsigned scx; + unsigned scy; + + unsigned hscroll; + unsigned vscroll; + + unsigned mosaic_vcounter; + unsigned mosaic_voffset; + + LayerWindow window; + + alwaysinline unsigned get_tile(unsigned hoffset, unsigned voffset); + void offset_per_tile(unsigned x, unsigned y, unsigned &hoffset, unsigned &voffset); + void scanline(); + void render(); + void render_mode7(); + + void serialize(serializer&); + Background(PPU &self, unsigned id); + ~Background(); + + PPU &self; + friend class PPU; +}; diff --git a/snes/alt/ppu-performance/background/mode7.cpp b/snes/alt/ppu-performance/background/mode7.cpp new file mode 100755 index 00000000..ef2b388c --- /dev/null +++ b/snes/alt/ppu-performance/background/mode7.cpp @@ -0,0 +1,105 @@ +#ifdef PPU_CPP + +#define Clip(x) (((x) & 0x2000) ? ((x) | ~0x03ff) : ((x) & 0x03ff)) + +void PPU::Background::render_mode7() { + signed px, py; + signed tx, ty, tile, palette; + + signed a = sclip<16>(self.regs.m7a); + signed b = sclip<16>(self.regs.m7b); + signed c = sclip<16>(self.regs.m7c); + signed d = sclip<16>(self.regs.m7d); + + signed cx = sclip<13>(self.regs.m7x); + signed cy = sclip<13>(self.regs.m7y); + signed hofs = sclip<13>(self.regs.mode7_hoffset); + signed vofs = sclip<13>(self.regs.mode7_voffset); + + signed y = (self.regs.mode7_vflip == false ? self.vcounter() : 255 - self.vcounter()); + + uint16 *mosaic_x, *mosaic_y; + if(id == ID::BG1) { + mosaic_x = mosaic_table[self.bg1.regs.mosaic]; + mosaic_y = mosaic_table[self.bg1.regs.mosaic]; + } else { + mosaic_x = mosaic_table[self.bg2.regs.mosaic]; + mosaic_y = mosaic_table[self.bg1.regs.mosaic]; + } + + unsigned priority0 = (priority0_enable ? regs.priority0 : 0); + unsigned priority1 = (priority1_enable ? regs.priority1 : 0); + if(priority0 + priority1 == 0) return; + + signed psx = ((a * Clip(hofs - cx)) & ~63) + ((b * Clip(vofs - cy)) & ~63) + ((b * mosaic_y[y]) & ~63) + (cx << 8); + signed psy = ((c * Clip(hofs - cx)) & ~63) + ((d * Clip(vofs - cy)) & ~63) + ((d * mosaic_y[y]) & ~63) + (cy << 8); + for(signed x = 0; x < 256; x++) { + px = (psx + (a * mosaic_x[x])) >> 8; + py = (psy + (c * mosaic_x[x])) >> 8; + + switch(self.regs.mode7_repeat) { + case 0: case 1: { + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = ppu.vram[(ty * 128 + tx) << 1]; + palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + break; + } + + case 2: { + if((px | py) & ~1023) { + palette = 0; + } else { + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = ppu.vram[(ty * 128 + tx) << 1]; + palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + } + break; + } + + case 3: { + if((px | py) & ~1023) { + tile = 0; + } else { + px &= 1023; + py &= 1023; + tx = ((px >> 3) & 127); + ty = ((py >> 3) & 127); + tile = ppu.vram[(ty * 128 + tx) << 1]; + } + palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + break; + } + } + + unsigned priority; + if(id == ID::BG1) { + priority = priority0; + } else { + priority = (palette & 0x80 ? priority1 : priority0); + palette &= 0x7f; + } + + if(palette == 0) continue; + unsigned plot_x = (self.regs.mode7_hflip == false ? x : 255 - x); + + unsigned color; + if(self.screen.regs.direct_color && id == ID::BG1) { + color = self.screen.get_direct_color(0, palette); + } else { + color = self.screen.get_palette(palette); + } + + if(regs.main_enable && !window.main[plot_x]) self.screen.output.plot_main(plot_x, color, priority, id); + if(regs.sub_enable && !window.sub[plot_x]) self.screen.output.plot_sub(plot_x, color, priority, id); + } +} + +#undef Clip + +#endif diff --git a/snes/alt/ppu-performance/cache/cache.cpp b/snes/alt/ppu-performance/cache/cache.cpp new file mode 100755 index 00000000..e51fc1a6 --- /dev/null +++ b/snes/alt/ppu-performance/cache/cache.cpp @@ -0,0 +1,123 @@ +#ifdef PPU_CPP + +uint8* PPU::Cache::tile_2bpp(unsigned tile) { + if(tilevalid[0][tile] == 0) { + tilevalid[0][tile] = 1; + uint8 *output = (uint8*)tiledata[0] + (tile << 6); + unsigned offset = tile << 4; + unsigned y = 8; + unsigned color, d0, d1; + while(y--) { + d0 = ppu.vram[offset + 0]; + d1 = ppu.vram[offset + 1]; + #define render_line(mask) \ + color = !!(d0 & mask) << 0; \ + color |= !!(d1 & mask) << 1; \ + *output++ = color + render_line(0x80); + render_line(0x40); + render_line(0x20); + render_line(0x10); + render_line(0x08); + render_line(0x04); + render_line(0x02); + render_line(0x01); + #undef render_line + offset += 2; + } + } + return tiledata[0] + (tile << 6); +} + +uint8* PPU::Cache::tile_4bpp(unsigned tile) { + if(tilevalid[1][tile] == 0) { + tilevalid[1][tile] = 1; + uint8 *output = (uint8*)tiledata[1] + (tile << 6); + unsigned offset = tile << 5; + unsigned y = 8; + unsigned color, d0, d1, d2, d3; + while(y--) { + d0 = ppu.vram[offset + 0]; + d1 = ppu.vram[offset + 1]; + d2 = ppu.vram[offset + 16]; + d3 = ppu.vram[offset + 17]; + #define render_line(mask) \ + color = !!(d0 & mask) << 0; \ + color |= !!(d1 & mask) << 1; \ + color |= !!(d2 & mask) << 2; \ + color |= !!(d3 & mask) << 3; \ + *output++ = color + render_line(0x80); + render_line(0x40); + render_line(0x20); + render_line(0x10); + render_line(0x08); + render_line(0x04); + render_line(0x02); + render_line(0x01); + #undef render_line + offset += 2; + } + } + return tiledata[1] + (tile << 6); +} + +uint8* PPU::Cache::tile_8bpp(unsigned tile) { + if(tilevalid[2][tile] == 0) { + tilevalid[2][tile] = 1; + uint8 *output = (uint8*)tiledata[2] + (tile << 6); + unsigned offset = tile << 6; + unsigned y = 8; + unsigned color, d0, d1, d2, d3, d4, d5, d6, d7; + while(y--) { + d0 = ppu.vram[offset + 0]; + d1 = ppu.vram[offset + 1]; + d2 = ppu.vram[offset + 16]; + d3 = ppu.vram[offset + 17]; + d4 = ppu.vram[offset + 32]; + d5 = ppu.vram[offset + 33]; + d6 = ppu.vram[offset + 48]; + d7 = ppu.vram[offset + 49]; + #define render_line(mask) \ + color = !!(d0 & mask) << 0; \ + color |= !!(d1 & mask) << 1; \ + color |= !!(d2 & mask) << 2; \ + color |= !!(d3 & mask) << 3; \ + color |= !!(d4 & mask) << 4; \ + color |= !!(d5 & mask) << 5; \ + color |= !!(d6 & mask) << 6; \ + color |= !!(d7 & mask) << 7; \ + *output++ = color + render_line(0x80); + render_line(0x40); + render_line(0x20); + render_line(0x10); + render_line(0x08); + render_line(0x04); + render_line(0x02); + render_line(0x01); + #undef render_line + offset += 2; + } + } + return tiledata[2] + (tile << 6); +} + +uint8* PPU::Cache::tile(unsigned bpp, unsigned tile) { + switch(bpp) { + case 0: return tile_2bpp(tile); + case 1: return tile_4bpp(tile); + case 2: return tile_8bpp(tile); + } +} + +PPU::Cache::Cache(PPU &self) : self(self) { + tiledata[0] = new uint8[262144](); + tiledata[1] = new uint8[131072](); + tiledata[2] = new uint8[ 65536](); + tilevalid[0] = new uint8[ 4096](); + tilevalid[1] = new uint8[ 2048](); + tilevalid[2] = new uint8[ 1024](); +} + +#endif diff --git a/snes/alt/ppu-performance/cache/cache.hpp b/snes/alt/ppu-performance/cache/cache.hpp new file mode 100755 index 00000000..b1f399fb --- /dev/null +++ b/snes/alt/ppu-performance/cache/cache.hpp @@ -0,0 +1,16 @@ +class Cache { +public: + uint8 *tiledata[3]; + uint8 *tilevalid[3]; + + uint8* tile_2bpp(unsigned tile); + uint8* tile_4bpp(unsigned tile); + uint8* tile_8bpp(unsigned tile); + uint8* tile(unsigned bpp, unsigned tile); + + void serialize(serializer&); + Cache(PPU &self); + + PPU &self; + friend class PPU; +}; diff --git a/snes/alt/ppu-performance/debugger/debugger.cpp b/snes/alt/ppu-performance/debugger/debugger.cpp new file mode 100755 index 00000000..c1a988c4 --- /dev/null +++ b/snes/alt/ppu-performance/debugger/debugger.cpp @@ -0,0 +1,7 @@ +#ifdef PPU_CPP + +bool PPUDebugger::property(unsigned id, string &name, string &value) { + return false; +} + +#endif diff --git a/snes/alt/ppu-performance/debugger/debugger.hpp b/snes/alt/ppu-performance/debugger/debugger.hpp new file mode 100755 index 00000000..9ce6a4e6 --- /dev/null +++ b/snes/alt/ppu-performance/debugger/debugger.hpp @@ -0,0 +1,4 @@ +class PPUDebugger : public PPU, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); +}; diff --git a/snes/alt/ppu-performance/mmio/mmio.cpp b/snes/alt/ppu-performance/mmio/mmio.cpp new file mode 100755 index 00000000..89416274 --- /dev/null +++ b/snes/alt/ppu-performance/mmio/mmio.cpp @@ -0,0 +1,891 @@ +#ifdef PPU_CPP + +void PPU::latch_counters() { + regs.hcounter = cpu.hdot(); + regs.vcounter = cpu.vcounter(); + regs.counters_latched = true; +} + +bool PPU::interlace() const { return display.interlace; } +bool PPU::overscan() const { return display.overscan; } +bool PPU::hires() const { return regs.pseudo_hires || regs.bgmode == 5 || regs.bgmode == 6; } + +uint16 PPU::get_vram_addr() { + uint16 addr = regs.vram_addr; + switch(regs.vram_mapping) { + case 0: break; + case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break; + case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break; + case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break; + } + return (addr << 1); +} + +uint8 PPU::vram_read(unsigned addr) { + if(regs.display_disable) return vram[addr]; + if(cpu.vcounter() >= display.height) return vram[addr]; + return 0x00; +} + +void PPU::vram_write(unsigned addr, uint8 data) { + if(regs.display_disable || cpu.vcounter() >= display.height) { + vram[addr] = data; + cache.tilevalid[0][addr >> 4] = false; + cache.tilevalid[1][addr >> 5] = false; + cache.tilevalid[2][addr >> 6] = false; + return; + } +} + +uint8 PPU::oam_read(unsigned addr) { + if(addr & 0x0200) addr &= 0x021f; + if(regs.display_disable) return oam[addr]; + if(cpu.vcounter() >= display.height) return oam[addr]; + return oam[0x0218]; +} + +void PPU::oam_write(unsigned addr, uint8 data) { + if(addr & 0x0200) addr &= 0x021f; + if(!regs.display_disable && cpu.vcounter() < display.height) addr = 0x0218; + oam[addr] = data; + sprite.update_list(addr, data); +} + +uint8 PPU::cgram_read(unsigned addr) { + return cgram[addr]; +} + +void PPU::cgram_write(unsigned addr, uint8 data) { + cgram[addr] = data; +} + +void PPU::mmio_update_video_mode() { + switch(regs.bgmode) { + case 0: { + bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11; + bg2.regs.mode = Background::Mode::BPP2; bg2.regs.priority0 = 7; bg2.regs.priority1 = 10; + bg3.regs.mode = Background::Mode::BPP2; bg3.regs.priority0 = 2; bg3.regs.priority1 = 5; + bg4.regs.mode = Background::Mode::BPP2; bg4.regs.priority0 = 1; bg4.regs.priority1 = 4; + sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12; + } break; + + case 1: { + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::BPP2; + bg4.regs.mode = Background::Mode::Inactive; + if(regs.bg3_priority) { + bg1.regs.priority0 = 5; bg1.regs.priority1 = 8; + bg2.regs.priority0 = 4; bg2.regs.priority1 = 7; + bg3.regs.priority0 = 1; bg3.regs.priority1 = 10; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 3; sprite.regs.priority2 = 6; sprite.regs.priority3 = 9; + } else { + bg1.regs.priority0 = 6; bg1.regs.priority1 = 9; + bg2.regs.priority0 = 5; bg2.regs.priority1 = 8; + bg3.regs.priority0 = 1; bg3.regs.priority1 = 3; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10; + } + } break; + + case 2: { + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + } break; + + case 3: { + bg1.regs.mode = Background::Mode::BPP8; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + } break; + + case 4: { + bg1.regs.mode = Background::Mode::BPP8; + bg2.regs.mode = Background::Mode::BPP2; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + } break; + + case 5: { + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP2; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + } break; + + case 6: { + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::Inactive; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 2; bg1.regs.priority1 = 5; + sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6; + } break; + + case 7: { + if(regs.mode7_extbg == false) { + bg1.regs.mode = Background::Mode::Mode7; + bg2.regs.mode = Background::Mode::Inactive; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 2; bg1.regs.priority1 = 2; + sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 5; + } else { + bg1.regs.mode = Background::Mode::Mode7; + bg2.regs.mode = Background::Mode::Mode7; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 3; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7; + } + } break; + } +} + +uint8 PPU::mmio_read(unsigned addr) { + cpu.synchronize_ppu(); + + switch(addr & 0xffff) { + case 0x2104: case 0x2105: case 0x2106: case 0x2108: case 0x2109: case 0x210a: + case 0x2114: case 0x2115: case 0x2116: case 0x2118: case 0x2119: case 0x211a: + case 0x2124: case 0x2125: case 0x2126: case 0x2128: case 0x2129: case 0x212a: { + return regs.ppu1_mdr; + } + + case 0x2134: { //MPYL + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = result >> 0; + return regs.ppu1_mdr; + } + + case 0x2135: { //MPYM + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = result >> 8; + return regs.ppu1_mdr; + } + + case 0x2136: { //MPYH + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = result >> 16; + return regs.ppu1_mdr; + } + + case 0x2137: { //SLHV + if(cpu.pio() & 0x80) latch_counters(); + return cpu.regs.mdr; + } + + case 0x2138: { //OAMDATAREAD + regs.ppu1_mdr = oam_read(regs.oam_addr); + regs.oam_addr = (regs.oam_addr + 1) & 0x03ff; + sprite.set_first(); + return regs.ppu1_mdr; + } + + case 0x2139: { //VMDATALREAD + regs.ppu1_mdr = regs.vram_readbuffer >> 0; + if(regs.vram_incmode == 0) { + uint16 addr = get_vram_addr(); + regs.vram_readbuffer = vram_read(addr + 0) << 0; + regs.vram_readbuffer |= vram_read(addr + 1) << 8; + regs.vram_addr += regs.vram_incsize; + } + return regs.ppu1_mdr; + } + + case 0x213a: { //VMDATAHREAD + regs.ppu1_mdr = regs.vram_readbuffer >> 8; + if(regs.vram_incmode == 1) { + uint16 addr = get_vram_addr(); + regs.vram_readbuffer = vram_read(addr + 0) << 0; + regs.vram_readbuffer |= vram_read(addr + 1) << 8; + regs.vram_addr += regs.vram_incsize; + } + return regs.ppu1_mdr; + } + + case 0x213b: { //CGDATAREAD + if((regs.cgram_addr & 1) == 0) { + regs.ppu2_mdr = cgram_read(regs.cgram_addr); + } else { + regs.ppu2_mdr = (regs.ppu2_mdr & 0x80) | (cgram_read(regs.cgram_addr) & 0x7f); + } + regs.cgram_addr = (regs.cgram_addr + 1) & 0x01ff; + return regs.ppu2_mdr; + } + + case 0x213c: { //OPHCT + if(regs.latch_hcounter == 0) { + regs.ppu2_mdr = regs.hcounter & 0xff; + } else { + regs.ppu2_mdr = (regs.ppu2_mdr & 0xfe) | (regs.hcounter >> 8); + } + regs.latch_hcounter ^= 1; + return regs.ppu2_mdr; + } + + case 0x213d: { //OPVCT + if(regs.latch_vcounter == 0) { + regs.ppu2_mdr = regs.vcounter & 0xff; + } else { + regs.ppu2_mdr = (regs.ppu2_mdr & 0xfe) | (regs.vcounter >> 8); + } + regs.latch_vcounter ^= 1; + return regs.ppu2_mdr; + } + + case 0x213e: { //STAT77 + regs.ppu1_mdr &= 0x10; + regs.ppu1_mdr |= sprite.regs.time_over << 7; + regs.ppu1_mdr |= sprite.regs.range_over << 6; + regs.ppu1_mdr |= 0x01; //version + return regs.ppu1_mdr; + } + + case 0x213f: { //STAT78 + regs.latch_hcounter = 0; + regs.latch_vcounter = 0; + + regs.ppu2_mdr &= 0x20; + regs.ppu2_mdr |= cpu.field() << 7; + if((cpu.pio() & 0x80) == 0) { + regs.ppu2_mdr |= 0x40; + } else if(regs.counters_latched) { + regs.ppu2_mdr |= 0x40; + regs.counters_latched = false; + } + regs.ppu2_mdr |= (system.region() == System::Region::NTSC ? 0 : 1) << 4; + regs.ppu2_mdr |= 0x03; //version + return regs.ppu2_mdr; + } + } + + return cpu.regs.mdr; +} + +void PPU::mmio_write(unsigned addr, uint8 data) { + cpu.synchronize_ppu(); + + switch(addr & 0xffff) { + case 0x2100: { //INIDISP + if(regs.display_disable && cpu.vcounter() == display.height) sprite.address_reset(); + regs.display_disable = data & 0x80; + regs.display_brightness = data & 0x0f; + return; + } + + case 0x2101: { //OBSEL + sprite.regs.base_size = (data >> 5) & 7; + sprite.regs.nameselect = (data >> 3) & 3; + sprite.regs.tiledata_addr = (data & 3) << 14; + sprite.list_valid = false; + return; + } + + case 0x2102: { //OAMADDL + regs.oam_baseaddr = (regs.oam_baseaddr & 0x0100) | (data << 0); + sprite.address_reset(); + return; + } + + case 0x2103: { //OAMADDH + regs.oam_priority = data & 0x80; + regs.oam_baseaddr = ((data & 1) << 8) | (regs.oam_baseaddr & 0x00ff); + sprite.address_reset(); + return; + } + + case 0x2104: { //OAMDATA + if((regs.oam_addr & 1) == 0) regs.oam_latchdata = data; + if(regs.oam_addr & 0x0200) { + oam_write(regs.oam_addr, data); + } else if((regs.oam_addr & 1) == 1) { + oam_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata); + oam_write((regs.oam_addr & ~1) + 1, data); + } + regs.oam_addr = (regs.oam_addr + 1) & 0x03ff; + sprite.set_first(); + return; + } + + case 0x2105: { //BGMODE + bg4.regs.tile_size = data & 0x80; + bg3.regs.tile_size = data & 0x40; + bg2.regs.tile_size = data & 0x20; + bg1.regs.tile_size = data & 0x10; + regs.bg3_priority = data & 0x08; + regs.bgmode = data & 0x07; + mmio_update_video_mode(); + return; + } + + case 0x2106: { //MOSAIC + unsigned mosaic_size = (data >> 4) & 15; + bg4.regs.mosaic = (data & 0x08 ? mosaic_size : 0); + bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0); + bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0); + bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0); + return; + } + + case 0x2107: { //BG1SC + bg1.regs.screen_addr = (data & 0x7c) << 9; + bg1.regs.screen_size = data & 3; + return; + } + + case 0x2108: { //BG2SC + bg2.regs.screen_addr = (data & 0x7c) << 9; + bg2.regs.screen_size = data & 3; + return; + } + + case 0x2109: { //BG3SC + bg3.regs.screen_addr = (data & 0x7c) << 9; + bg3.regs.screen_size = data & 3; + return; + } + + case 0x210a: { //BG4SC + bg4.regs.screen_addr = (data & 0x7c) << 9; + bg4.regs.screen_size = data & 3; + return; + } + + case 0x210b: { //BG12NBA + bg1.regs.tiledata_addr = (data & 0x07) << 13; + bg2.regs.tiledata_addr = (data & 0x70) << 9; + return; + } + + case 0x210c: { //BG34NBA + bg3.regs.tiledata_addr = (data & 0x07) << 13; + bg4.regs.tiledata_addr = (data & 0x70) << 9; + return; + } + + case 0x210d: { //BG1HOFS + regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + + bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; + return; + } + + case 0x210e: { //BG1VOFS + regs.mode7_voffset = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + + bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; + return; + } + + case 0x210f: { //BG2HOFS + bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; + return; + } + + case 0x2110: { //BG2VOFS + bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; + return; + } + + case 0x2111: { //BG3HOFS + bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; + return; + } + + case 0x2112: { //BG3VOFS + bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; + return; + } + + case 0x2113: { //BG4HOFS + bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; + return; + } + + case 0x2114: { //BG4VOFS + bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; + return; + } + + case 0x2115: { //VMAIN + regs.vram_incmode = data & 0x80; + regs.vram_mapping = (data >> 2) & 3; + switch(data & 3) { + case 0: regs.vram_incsize = 1; break; + case 1: regs.vram_incsize = 32; break; + case 2: regs.vram_incsize = 128; break; + case 3: regs.vram_incsize = 128; break; + } + return; + } + + case 0x2116: { //VMADDL + regs.vram_addr = (regs.vram_addr & 0xff00) | (data << 0); + uint16 addr = get_vram_addr(); + regs.vram_readbuffer = vram_read(addr + 0) << 0; + regs.vram_readbuffer |= vram_read(addr + 1) << 8; + return; + } + + case 0x2117: { //VMADDH + regs.vram_addr = (data << 8) | (regs.vram_addr & 0x00ff); + uint16 addr = get_vram_addr(); + regs.vram_readbuffer = vram_read(addr + 0) << 0; + regs.vram_readbuffer |= vram_read(addr + 1) << 8; + return; + } + + case 0x2118: { //VMDATAL + vram_write(get_vram_addr() + 0, data); + if(regs.vram_incmode == 0) regs.vram_addr += regs.vram_incsize; + return; + } + + case 0x2119: { //VMDATAH + vram_write(get_vram_addr() + 1, data); + if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize; + return; + } + + case 0x211a: { //M7SEL + regs.mode7_repeat = (data >> 6) & 3; + regs.mode7_vflip = data & 0x02; + regs.mode7_hflip = data & 0x01; + return; + } + + case 0x211b: { //M7A + regs.m7a = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + case 0x211c: { //M7B + regs.m7b = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + case 0x211d: { //M7C + regs.m7c = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + case 0x211e: { //M7D + regs.m7d = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + case 0x211f: { //M7X + regs.m7x = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + case 0x2120: { //M7Y + regs.m7y = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + case 0x2121: { //CGADD + regs.cgram_addr = data << 1; + return; + } + + case 0x2122: { //CGDATA + if((regs.cgram_addr & 1) == 0) { + regs.cgram_latchdata = data; + } else { + cgram_write((regs.cgram_addr & ~1) + 0, regs.cgram_latchdata); + cgram_write((regs.cgram_addr & ~1) + 1, data & 0x7f); + } + regs.cgram_addr = (regs.cgram_addr + 1) & 0x01ff; + return; + } + + case 0x2123: { //W12SEL + bg2.window.two_enable = data & 0x80; + bg2.window.two_invert = data & 0x40; + bg2.window.one_enable = data & 0x20; + bg2.window.one_invert = data & 0x10; + bg1.window.two_enable = data & 0x08; + bg1.window.two_invert = data & 0x04; + bg1.window.one_enable = data & 0x02; + bg1.window.one_invert = data & 0x01; + return; + } + + case 0x2124: { //W34SEL + bg4.window.two_enable = data & 0x80; + bg4.window.two_invert = data & 0x40; + bg4.window.one_enable = data & 0x20; + bg4.window.one_invert = data & 0x10; + bg3.window.two_enable = data & 0x08; + bg3.window.two_invert = data & 0x04; + bg3.window.one_enable = data & 0x02; + bg3.window.one_invert = data & 0x01; + return; + } + + case 0x2125: { //WOBJSEL + screen.window.two_enable = data & 0x80; + screen.window.two_invert = data & 0x40; + screen.window.one_enable = data & 0x20; + screen.window.one_invert = data & 0x10; + sprite.window.two_enable = data & 0x08; + sprite.window.two_invert = data & 0x04; + sprite.window.one_enable = data & 0x02; + sprite.window.one_invert = data & 0x01; + return; + } + + case 0x2126: { //WH0 + regs.window_one_left = data; + return; + } + + case 0x2127: { //WH1 + regs.window_one_right = data; + return; + } + + case 0x2128: { //WH2 + regs.window_two_left = data; + return; + } + + case 0x2129: { //WH3 + regs.window_two_right = data; + return; + } + + case 0x212a: { //WBGLOG + bg4.window.mask = (data >> 6) & 3; + bg3.window.mask = (data >> 4) & 3; + bg2.window.mask = (data >> 2) & 3; + bg1.window.mask = (data >> 0) & 3; + return; + } + + case 0x212b: { //WOBJLOG + screen.window.mask = (data >> 2) & 3; + sprite.window.mask = (data >> 0) & 3; + return; + } + + case 0x212c: { //TM + sprite.regs.main_enable = data & 0x10; + bg4.regs.main_enable = data & 0x08; + bg3.regs.main_enable = data & 0x04; + bg2.regs.main_enable = data & 0x02; + bg1.regs.main_enable = data & 0x01; + return; + } + + case 0x212d: { //TS + sprite.regs.sub_enable = data & 0x10; + bg4.regs.sub_enable = data & 0x08; + bg3.regs.sub_enable = data & 0x04; + bg2.regs.sub_enable = data & 0x02; + bg1.regs.sub_enable = data & 0x01; + return; + } + + case 0x212e: { //TMW + sprite.window.main_enable = data & 0x10; + bg4.window.main_enable = data & 0x08; + bg3.window.main_enable = data & 0x04; + bg2.window.main_enable = data & 0x02; + bg1.window.main_enable = data & 0x01; + return; + } + + case 0x212f: { //TSW + sprite.window.sub_enable = data & 0x10; + bg4.window.sub_enable = data & 0x08; + bg3.window.sub_enable = data & 0x04; + bg2.window.sub_enable = data & 0x02; + bg1.window.sub_enable = data & 0x01; + return; + } + + case 0x2130: { //CGWSEL + screen.window.main_mask = (data >> 6) & 3; + screen.window.sub_mask = (data >> 4) & 3; + screen.regs.addsub_mode = data & 0x02; + screen.regs.direct_color = data & 0x01; + return; + } + + case 0x2131: { //CGADDSUB + screen.regs.color_mode = data & 0x80; + screen.regs.color_halve = data & 0x40; + screen.regs.color_enable[6] = data & 0x20; + screen.regs.color_enable[5] = data & 0x10; + screen.regs.color_enable[4] = data & 0x10; + screen.regs.color_enable[3] = data & 0x08; + screen.regs.color_enable[2] = data & 0x04; + screen.regs.color_enable[1] = data & 0x02; + screen.regs.color_enable[0] = data & 0x01; + return; + } + + case 0x2132: { //COLDATA + if(data & 0x80) screen.regs.color_b = data & 0x1f; + if(data & 0x40) screen.regs.color_g = data & 0x1f; + if(data & 0x20) screen.regs.color_r = data & 0x1f; + screen.regs.color = (screen.regs.color_b << 10) | (screen.regs.color_g << 5) | (screen.regs.color_r << 0); + return; + } + + case 0x2133: { //SETINI + regs.mode7_extbg = data & 0x40; + regs.pseudo_hires = data & 0x08; + regs.overscan = data & 0x04; + sprite.regs.interlace = data & 0x02; + regs.interlace = data & 0x01; + mmio_update_video_mode(); + sprite.list_valid = false; + return; + } + } +} + +void PPU::mmio_reset() { + //internal + regs.ppu1_mdr = 0; + regs.ppu2_mdr = 0; + + regs.vram_readbuffer = 0; + regs.oam_latchdata = 0; + regs.cgram_latchdata = 0; + regs.bgofs_latchdata = 0; + regs.mode7_latchdata = 0; + + regs.counters_latched = 0; + regs.latch_hcounter = 0; + regs.latch_vcounter = 0; + + sprite.regs.first_sprite = 0; + sprite.list_valid = false; + + //$2100 + regs.display_disable = true; + regs.display_brightness = 0; + + //$2101 + sprite.regs.base_size = 0; + sprite.regs.nameselect = 0; + sprite.regs.tiledata_addr = 0; + + //$2102-$2103 + regs.oam_baseaddr = 0; + regs.oam_addr = 0; + regs.oam_priority = 0; + + //$2105 + bg4.regs.tile_size = 0; + bg3.regs.tile_size = 0; + bg2.regs.tile_size = 0; + bg1.regs.tile_size = 0; + regs.bg3_priority = 0; + regs.bgmode = 0; + + //$2106 + bg4.regs.mosaic = 0; + bg3.regs.mosaic = 0; + bg2.regs.mosaic = 0; + bg1.regs.mosaic = 0; + + //$2107-$210a + bg1.regs.screen_addr = 0; + bg1.regs.screen_size = 0; + bg2.regs.screen_addr = 0; + bg2.regs.screen_size = 0; + bg3.regs.screen_addr = 0; + bg3.regs.screen_size = 0; + bg4.regs.screen_addr = 0; + bg4.regs.screen_size = 0; + + //$210b-$210c + bg1.regs.tiledata_addr = 0; + bg2.regs.tiledata_addr = 0; + bg3.regs.tiledata_addr = 0; + bg4.regs.tiledata_addr = 0; + + //$210d-$2114 + regs.mode7_hoffset = 0; + regs.mode7_voffset = 0; + bg1.regs.hoffset = 0; + bg1.regs.voffset = 0; + bg2.regs.hoffset = 0; + bg2.regs.voffset = 0; + bg3.regs.hoffset = 0; + bg3.regs.voffset = 0; + bg4.regs.hoffset = 0; + bg4.regs.voffset = 0; + + //$2115 + regs.vram_incmode = 0; + regs.vram_mapping = 0; + regs.vram_incsize = 1; + + //$2116-$2117 + regs.vram_addr = 0; + + //$211a + regs.mode7_repeat = 0; + regs.mode7_vflip = 0; + regs.mode7_hflip = 0; + + //$211b-$2120 + regs.m7a = 0; + regs.m7b = 0; + regs.m7c = 0; + regs.m7d = 0; + regs.m7x = 0; + regs.m7y = 0; + + //$2121 + regs.cgram_addr = 0; + + //$2123-$2125 + bg1.window.one_enable = 0; + bg1.window.one_invert = 0; + bg1.window.two_enable = 0; + bg1.window.two_invert = 0; + + bg2.window.one_enable = 0; + bg2.window.one_invert = 0; + bg2.window.two_enable = 0; + bg2.window.two_invert = 0; + + bg3.window.one_enable = 0; + bg3.window.one_invert = 0; + bg3.window.two_enable = 0; + bg3.window.two_invert = 0; + + bg4.window.one_enable = 0; + bg4.window.one_invert = 0; + bg4.window.two_enable = 0; + bg4.window.two_invert = 0; + + sprite.window.one_enable = 0; + sprite.window.one_invert = 0; + sprite.window.two_enable = 0; + sprite.window.two_invert = 0; + + screen.window.one_enable = 0; + screen.window.one_invert = 0; + screen.window.two_enable = 0; + screen.window.two_invert = 0; + + //$2126-$2129 + regs.window_one_left = 0; + regs.window_one_right = 0; + regs.window_two_left = 0; + regs.window_two_right = 0; + + //$212a-$212b + bg1.window.mask = 0; + bg2.window.mask = 0; + bg3.window.mask = 0; + bg4.window.mask = 0; + sprite.window.mask = 0; + screen.window.mask = 0; + + //$212c + bg1.regs.main_enable = 0; + bg2.regs.main_enable = 0; + bg3.regs.main_enable = 0; + bg4.regs.main_enable = 0; + sprite.regs.main_enable = 0; + + //$212d + bg1.regs.sub_enable = 0; + bg2.regs.sub_enable = 0; + bg3.regs.sub_enable = 0; + bg4.regs.sub_enable = 0; + sprite.regs.sub_enable = 0; + + //$212e + bg1.window.main_enable = 0; + bg2.window.main_enable = 0; + bg3.window.main_enable = 0; + bg4.window.main_enable = 0; + sprite.window.main_enable = 0; + + //$212f + bg1.window.sub_enable = 0; + bg2.window.sub_enable = 0; + bg3.window.sub_enable = 0; + bg4.window.sub_enable = 0; + sprite.window.sub_enable = 0; + + //$2130 + screen.window.main_mask = 0; + screen.window.sub_mask = 0; + screen.regs.addsub_mode = 0; + screen.regs.direct_color = 0; + + //$2131 + screen.regs.color_mode = 0; + screen.regs.color_halve = 0; + screen.regs.color_enable[6] = 0; + screen.regs.color_enable[5] = 0; + screen.regs.color_enable[4] = 0; + screen.regs.color_enable[3] = 0; + screen.regs.color_enable[2] = 0; + screen.regs.color_enable[1] = 0; + screen.regs.color_enable[0] = 0; + + //$2132 + screen.regs.color_b = 0; + screen.regs.color_g = 0; + screen.regs.color_r = 0; + screen.regs.color = 0; + + //$2133 + regs.mode7_extbg = 0; + regs.pseudo_hires = 0; + regs.overscan = 0; + sprite.regs.interlace = 0; + regs.interlace = 0; + + //$213e + sprite.regs.time_over = 0; + sprite.regs.range_over = 0; + + mmio_update_video_mode(); +} + +#endif diff --git a/snes/alt/ppu-performance/mmio/mmio.hpp b/snes/alt/ppu-performance/mmio/mmio.hpp new file mode 100755 index 00000000..36b5af4d --- /dev/null +++ b/snes/alt/ppu-performance/mmio/mmio.hpp @@ -0,0 +1,95 @@ +public: + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + +private: + +struct Regs { + //internal + uint8 ppu1_mdr; + uint8 ppu2_mdr; + + uint16 vram_readbuffer; + uint8 oam_latchdata; + uint8 cgram_latchdata; + uint8 bgofs_latchdata; + uint8 mode7_latchdata; + + bool counters_latched; + bool latch_hcounter; + bool latch_vcounter; + + //$2100 + bool display_disable; + unsigned display_brightness; + + //$2102-$2103 + uint16 oam_baseaddr; + uint16 oam_addr; + bool oam_priority; + + //$2105 + bool bg3_priority; + unsigned bgmode; + + //$210d + uint16 mode7_hoffset; + + //$210e + uint16 mode7_voffset; + + //$2115 + bool vram_incmode; + unsigned vram_mapping; + unsigned vram_incsize; + + //$2116-$2117 + uint16 vram_addr; + + //$211a + unsigned mode7_repeat; + bool mode7_vflip; + bool mode7_hflip; + + //$211b-$2120 + uint16 m7a; + uint16 m7b; + uint16 m7c; + uint16 m7d; + uint16 m7x; + uint16 m7y; + + //$2121 + uint16 cgram_addr; + + //$2126-$212a + unsigned window_one_left; + unsigned window_one_right; + unsigned window_two_left; + unsigned window_two_right; + + //$2133 + bool mode7_extbg; + bool pseudo_hires; + bool overscan; + bool interlace; + + //$213c + uint16 hcounter; + + //$213d + uint16 vcounter; +} regs; + +uint16 get_vram_addr(); +uint8 vram_read(unsigned addr); +void vram_write(unsigned addr, uint8 data); + +uint8 oam_read(unsigned addr); +void oam_write(unsigned addr, uint8 data); + +uint8 cgram_read(unsigned addr); +void cgram_write(unsigned addr, uint8 data); + +void mmio_update_video_mode(); +void mmio_reset(); diff --git a/snes/alt/ppu-performance/ppu.cpp b/snes/alt/ppu-performance/ppu.cpp new file mode 100755 index 00000000..7c231bc0 --- /dev/null +++ b/snes/alt/ppu-performance/ppu.cpp @@ -0,0 +1,155 @@ +#include + +#define PPU_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + PPUDebugger ppu; +#else + PPU ppu; +#endif + +#include "mmio/mmio.cpp" +#include "window/window.cpp" +#include "cache/cache.cpp" +#include "background/background.cpp" +#include "sprite/sprite.cpp" +#include "screen/screen.cpp" +#include "serialization.cpp" + +void PPU::step(unsigned clocks) { + clock += clocks; +} + +void PPU::synchronize_cpu() { + if(CPU::Threaded == true) { + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +} + +void PPU::Enter() { ppu.enter(); } + +void PPU::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + scanline(); + if(vcounter() < display.height && vcounter()) { + add_clocks(512); + render_scanline(); + add_clocks(lineclocks() - 512); + } else { + add_clocks(lineclocks()); + } + } +} + +void PPU::add_clocks(unsigned clocks) { + tick(clocks); + step(clocks); + synchronize_cpu(); +} + +void PPU::render_scanline() { + if(display.framecounter) return; //skip this frame? + bg1.scanline(); + bg2.scanline(); + bg3.scanline(); + bg4.scanline(); + if(regs.display_disable) return screen.render_black(); + screen.scanline(); + bg1.render(); + bg2.render(); + bg3.render(); + bg4.render(); + sprite.render(); + screen.render(); +} + +void PPU::scanline() { + display.width = !hires() ? 256 : 512; + display.height = !overscan() ? 225 : 240; + if(vcounter() == 0) frame(); + if(vcounter() == display.height && regs.display_disable == false) sprite.address_reset(); +} + +void PPU::frame() { + sprite.frame(); + system.frame(); + display.interlace = regs.interlace; + display.overscan = regs.overscan; + display.framecounter = display.frameskip == 0 ? 0 : (display.framecounter + 1) % display.frameskip; +} + +void PPU::enable() { + function read = { &PPU::mmio_read, (PPU*)&ppu }; + function write = { &PPU::mmio_write, (PPU*)&ppu }; + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write); +} + +void PPU::power() { + for(auto &n : vram) n = 0; + for(auto &n : oam) n = 0; + for(auto &n : cgram) n = 0; + reset(); +} + +void PPU::reset() { + create(Enter, system.cpu_frequency()); + PPUcounter::reset(); + memset(surface, 0, 512 * 512 * sizeof(uint32)); + mmio_reset(); + display.interlace = false; + display.overscan = false; +} + +void PPU::layer_enable(unsigned layer, unsigned priority, bool enable) { + switch(layer * 4 + priority) { + case 0: bg1.priority0_enable = enable; break; + case 1: bg1.priority1_enable = enable; break; + case 4: bg2.priority0_enable = enable; break; + case 5: bg2.priority1_enable = enable; break; + case 8: bg3.priority0_enable = enable; break; + case 9: bg3.priority1_enable = enable; break; + case 12: bg4.priority0_enable = enable; break; + case 13: bg4.priority1_enable = enable; break; + case 16: sprite.priority0_enable = enable; break; + case 17: sprite.priority1_enable = enable; break; + case 18: sprite.priority2_enable = enable; break; + case 19: sprite.priority3_enable = enable; break; + } +} + +void PPU::set_frameskip(unsigned frameskip) { + display.frameskip = frameskip; + display.framecounter = 0; +} + +PPU::PPU() : +cache(*this), +bg1(*this, Background::ID::BG1), +bg2(*this, Background::ID::BG2), +bg3(*this, Background::ID::BG3), +bg4(*this, Background::ID::BG4), +sprite(*this), +screen(*this) { + surface = new uint32[512 * 512]; + output = surface + 16 * 512; + display.width = 256; + display.height = 224; + display.frameskip = 0; + display.framecounter = 0; +} + +PPU::~PPU() { + delete[] surface; +} + +} diff --git a/snes/alt/ppu-performance/ppu.hpp b/snes/alt/ppu-performance/ppu.hpp new file mode 100755 index 00000000..37eb991e --- /dev/null +++ b/snes/alt/ppu-performance/ppu.hpp @@ -0,0 +1,74 @@ +class PPU : public Processor, public PPUcounter { +public: + uint8 vram[64 * 1024]; + uint8 oam[544]; + uint8 cgram[512]; + + enum : bool { Threaded = true }; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_cpu(); + + void latch_counters(); + bool interlace() const; + bool overscan() const; + bool hires() const; + + void enter(); + void enable(); + void power(); + void reset(); + void scanline(); + void frame(); + + void layer_enable(unsigned layer, unsigned priority, bool enable); + void set_frameskip(unsigned frameskip); + + void serialize(serializer&); + PPU(); + ~PPU(); + +private: + uint32 *surface; + uint32 *output; + + #include "mmio/mmio.hpp" + #include "window/window.hpp" + #include "cache/cache.hpp" + #include "background/background.hpp" + #include "sprite/sprite.hpp" + #include "screen/screen.hpp" + + Cache cache; + Background bg1; + Background bg2; + Background bg3; + Background bg4; + Sprite sprite; + Screen screen; + + struct Display { + bool interlace; + bool overscan; + unsigned width; + unsigned height; + unsigned frameskip; + unsigned framecounter; + } display; + + static void Enter(); + void add_clocks(unsigned clocks); + void render_scanline(); + + friend class PPU::Cache; + friend class PPU::Background; + friend class PPU::Sprite; + friend class PPU::Screen; + friend class Video; +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern PPUDebugger ppu; +#else + extern PPU ppu; +#endif diff --git a/snes/alt/ppu-performance/screen/screen.cpp b/snes/alt/ppu-performance/screen/screen.cpp new file mode 100755 index 00000000..7939f243 --- /dev/null +++ b/snes/alt/ppu-performance/screen/screen.cpp @@ -0,0 +1,155 @@ +#ifdef PPU_CPP + +unsigned PPU::Screen::get_palette(unsigned color) { + #if defined(ARCH_LSB) + return ((uint16*)ppu.cgram)[color]; + #else + color <<= 1; + return (ppu.cgram[color + 0] << 0) + (ppu.cgram[color + 1] << 8); + #endif +} + +unsigned PPU::Screen::get_direct_color(unsigned p, unsigned t) { + return ((t & 7) << 2) | ((p & 1) << 1) | + (((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) | + ((t >> 6) << 13) | ((p >> 2) << 12); +} + +uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) { + if(!regs.color_mode) { + if(!halve) { + unsigned sum = x + y; + unsigned carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; + return (sum - carry) | (carry - (carry >> 5)); + } else { + return (x + y - ((x ^ y) & 0x0421)) >> 1; + } + } else { + unsigned diff = x - y + 0x8420; + unsigned borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420; + if(!halve) { + return (diff - borrow) & (borrow - (borrow >> 5)); + } else { + return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1; + } + } +} + +void PPU::Screen::scanline() { + unsigned main_color = get_palette(0); + unsigned sub_color = (self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) + ? regs.color : main_color; + + for(unsigned x = 0; x < 256; x++) { + output.main[x].color = main_color; + output.main[x].priority = 0; + output.main[x].source = 6; + + output.sub[x].color = sub_color; + output.sub[x].priority = 0; + output.sub[x].source = 6; + } + + window.render(0); + window.render(1); +} + +void PPU::Screen::render_black() { + uint32 *data = self.output + self.vcounter() * 1024; + if(self.interlace() && self.field()) data += 512; + memset(data, 0, self.display.width << 2); +} + +uint16 PPU::Screen::get_pixel_main(unsigned x) { + auto main = output.main[x]; + auto sub = output.sub[x]; + + if(!regs.addsub_mode) { + sub.source = 6; + sub.color = regs.color; + } + + if(!window.main[x]) { + if(!window.sub[x]) { + return 0x0000; + } + main.color = 0x0000; + } + + if(main.source != 5 && regs.color_enable[main.source] && window.sub[x]) { + bool halve = false; + if(regs.color_halve && window.main[x]) { + if(!regs.addsub_mode || sub.source != 6) halve = true; + } + return addsub(main.color, sub.color, halve); + } + + return main.color; +} + +uint16 PPU::Screen::get_pixel_sub(unsigned x) { + auto main = output.sub[x]; + auto sub = output.main[x]; + + if(!regs.addsub_mode) { + sub.source = 6; + sub.color = regs.color; + } + + if(!window.main[x]) { + if(!window.sub[x]) { + return 0x0000; + } + main.color = 0x0000; + } + + if(main.source != 5 && regs.color_enable[main.source] && window.sub[x]) { + bool halve = false; + if(regs.color_halve && window.main[x]) { + if(!regs.addsub_mode || sub.source != 6) halve = true; + } + return addsub(main.color, sub.color, halve); + } + + return main.color; +} + +void PPU::Screen::render() { + uint32 *data = self.output + self.vcounter() * 1024; + if(self.interlace() && self.field()) data += 512; + + if(!self.regs.pseudo_hires && self.regs.bgmode != 5 && self.regs.bgmode != 6) { + for(unsigned i = 0; i < 256; i++) { + data[i] = (self.regs.display_brightness << 15) | get_pixel_main(i); + } + } else { + for(unsigned i = 0; i < 256; i++) { + *data++ = (self.regs.display_brightness << 15) | get_pixel_sub(i); + *data++ = (self.regs.display_brightness << 15) | get_pixel_main(i); + } + } +} + +PPU::Screen::Screen(PPU &self) : self(self) { +} + +PPU::Screen::~Screen() { +} + +void PPU::Screen::Output::plot_main(unsigned x, unsigned color, unsigned priority, unsigned source) { + if(priority > main[x].priority) { + main[x].color = color; + main[x].priority = priority; + main[x].source = source; + } +} + +void PPU::Screen::Output::plot_sub(unsigned x, unsigned color, unsigned priority, unsigned source) { + if(priority > sub[x].priority) { + sub[x].color = color; + sub[x].priority = priority; + sub[x].source = source; + } +} + +#endif diff --git a/snes/alt/ppu-performance/screen/screen.hpp b/snes/alt/ppu-performance/screen/screen.hpp new file mode 100755 index 00000000..e93d3cd4 --- /dev/null +++ b/snes/alt/ppu-performance/screen/screen.hpp @@ -0,0 +1,44 @@ +class Screen { + struct Regs { + bool addsub_mode; + bool direct_color; + + bool color_mode; + bool color_halve; + bool color_enable[7]; + + unsigned color_b; + unsigned color_g; + unsigned color_r; + unsigned color; + } regs; + + struct Output { + struct Pixel { + unsigned color; + unsigned priority; + unsigned source; + } main[256], sub[256]; + + alwaysinline void plot_main(unsigned x, unsigned color, unsigned priority, unsigned source); + alwaysinline void plot_sub(unsigned x, unsigned color, unsigned priority, unsigned source); + } output; + + ColorWindow window; + + alwaysinline unsigned get_palette(unsigned color); + unsigned get_direct_color(unsigned palette, unsigned tile); + alwaysinline uint16 addsub(unsigned x, unsigned y, bool halve); + void scanline(); + void render_black(); + alwaysinline uint16 get_pixel_main(unsigned x); + alwaysinline uint16 get_pixel_sub(unsigned x); + void render(); + + void serialize(serializer&); + Screen(PPU &self); + ~Screen(); + + PPU &self; + friend class PPU; +}; diff --git a/snes/alt/ppu-performance/serialization.cpp b/snes/alt/ppu-performance/serialization.cpp new file mode 100755 index 00000000..cc4c10c1 --- /dev/null +++ b/snes/alt/ppu-performance/serialization.cpp @@ -0,0 +1,249 @@ +#ifdef PPU_CPP + +void PPUcounter::serialize(serializer &s) { + s.integer(status.interlace); + s.integer(status.field); + s.integer(status.vcounter); + s.integer(status.hcounter); + + s.array(history.field); + s.array(history.vcounter); + s.array(history.hcounter); + s.integer(history.index); +} + +void PPU::serialize(serializer &s) { + Processor::serialize(s); + PPUcounter::serialize(s); + + s.array(vram); + s.array(oam); + s.array(cgram); + + cache.serialize(s); + bg1.serialize(s); + bg2.serialize(s); + bg3.serialize(s); + bg4.serialize(s); + sprite.serialize(s); + screen.serialize(s); + + s.integer(display.interlace); + s.integer(display.overscan); + s.integer(display.width); + s.integer(display.height); + + s.integer(regs.ppu1_mdr); + s.integer(regs.ppu2_mdr); + + s.integer(regs.vram_readbuffer); + s.integer(regs.oam_latchdata); + s.integer(regs.cgram_latchdata); + s.integer(regs.bgofs_latchdata); + s.integer(regs.mode7_latchdata); + + s.integer(regs.counters_latched); + s.integer(regs.latch_hcounter); + s.integer(regs.latch_vcounter); + + s.integer(regs.display_disable); + s.integer(regs.display_brightness); + + s.integer(regs.oam_baseaddr); + s.integer(regs.oam_addr); + s.integer(regs.oam_priority); + + s.integer(regs.bg3_priority); + s.integer(regs.bgmode); + + s.integer(regs.mode7_hoffset); + + s.integer(regs.mode7_voffset); + + s.integer(regs.vram_incmode); + s.integer(regs.vram_mapping); + s.integer(regs.vram_incsize); + + s.integer(regs.vram_addr); + + s.integer(regs.mode7_repeat); + s.integer(regs.mode7_vflip); + s.integer(regs.mode7_hflip); + + s.integer(regs.m7a); + s.integer(regs.m7b); + s.integer(regs.m7c); + s.integer(regs.m7d); + s.integer(regs.m7x); + s.integer(regs.m7y); + + s.integer(regs.cgram_addr); + + s.integer(regs.window_one_left); + s.integer(regs.window_one_right); + s.integer(regs.window_two_left); + s.integer(regs.window_two_right); + + s.integer(regs.mode7_extbg); + s.integer(regs.pseudo_hires); + s.integer(regs.overscan); + s.integer(regs.interlace); + + s.integer(regs.hcounter); + + s.integer(regs.vcounter); +} + +void PPU::Cache::serialize(serializer &s) { + //rather than save ~512KB worth of cached tiledata, invalidate it all + for(unsigned i = 0; i < 4096; i++) tilevalid[0][i] = false; + for(unsigned i = 0; i < 2048; i++) tilevalid[1][i] = false; + for(unsigned i = 0; i < 1024; i++) tilevalid[2][i] = false; +} + +void PPU::Background::serialize(serializer &s) { + s.integer(regs.mode); + s.integer(regs.priority0); + s.integer(regs.priority1); + + s.integer(regs.tile_size); + s.integer(regs.mosaic); + + s.integer(regs.screen_addr); + s.integer(regs.screen_size); + s.integer(regs.tiledata_addr); + + s.integer(regs.hoffset); + s.integer(regs.voffset); + + s.integer(regs.main_enable); + s.integer(regs.sub_enable); + + s.integer(hires); + s.integer(width); + + s.integer(tile_width); + s.integer(tile_height); + + s.integer(mask_x); + s.integer(mask_y); + + s.integer(scx); + s.integer(scy); + + s.integer(hscroll); + s.integer(vscroll); + + s.integer(mosaic_vcounter); + s.integer(mosaic_voffset); + + window.serialize(s); +} + +void PPU::Sprite::serialize(serializer &s) { + s.integer(regs.priority0); + s.integer(regs.priority1); + s.integer(regs.priority2); + s.integer(regs.priority3); + + s.integer(regs.base_size); + s.integer(regs.nameselect); + s.integer(regs.tiledata_addr); + s.integer(regs.first_sprite); + + s.integer(regs.main_enable); + s.integer(regs.sub_enable); + + s.integer(regs.interlace); + + s.integer(regs.time_over); + s.integer(regs.range_over); + + for(unsigned i = 0; i < 128; i++) { + s.integer(list[i].width); + s.integer(list[i].height); + s.integer(list[i].x); + s.integer(list[i].y); + s.integer(list[i].character); + s.integer(list[i].use_nameselect); + s.integer(list[i].vflip); + s.integer(list[i].hflip); + s.integer(list[i].palette); + s.integer(list[i].priority); + s.integer(list[i].size); + } + s.integer(list_valid); + + s.array(itemlist); + for(unsigned i = 0; i < 34; i++) { + s.integer(tilelist[i].x); + s.integer(tilelist[i].y); + s.integer(tilelist[i].priority); + s.integer(tilelist[i].palette); + s.integer(tilelist[i].tile); + s.integer(tilelist[i].hflip); + } + + s.array(output.palette); + s.array(output.priority); + + window.serialize(s); +} + +void PPU::Screen::serialize(serializer &s) { + s.integer(regs.addsub_mode); + s.integer(regs.direct_color); + + s.integer(regs.color_mode); + s.integer(regs.color_halve); + s.array(regs.color_enable); + + s.integer(regs.color_b); + s.integer(regs.color_g); + s.integer(regs.color_r); + s.integer(regs.color); + + for(unsigned i = 0; i < 256; i++) { + s.integer(output.main[i].color); + s.integer(output.main[i].priority); + s.integer(output.main[i].source); + + s.integer(output.sub[i].color); + s.integer(output.sub[i].priority); + s.integer(output.sub[i].source); + } + + window.serialize(s); +} + +void PPU::LayerWindow::serialize(serializer &s) { + s.integer(one_enable); + s.integer(one_invert); + s.integer(two_enable); + s.integer(two_invert); + + s.integer(mask); + + s.integer(main_enable); + s.integer(sub_enable); + + s.array(main); + s.array(sub); +} + +void PPU::ColorWindow::serialize(serializer &s) { + s.integer(one_enable); + s.integer(one_invert); + s.integer(two_enable); + s.integer(two_invert); + + s.integer(mask); + + s.integer(main_mask); + s.integer(sub_mask); + + s.array(main); + s.array(sub); +} + +#endif diff --git a/snes/alt/ppu-performance/sprite/sprite.cpp b/snes/alt/ppu-performance/sprite/sprite.cpp new file mode 100755 index 00000000..222739cd --- /dev/null +++ b/snes/alt/ppu-performance/sprite/sprite.cpp @@ -0,0 +1,190 @@ +#ifdef PPU_CPP + +void PPU::Sprite::frame() { + regs.time_over = false; + regs.range_over = false; +} + +void PPU::Sprite::update_list(unsigned addr, uint8 data) { + if(addr < 0x0200) { + unsigned i = addr >> 2; + switch(addr & 3) { + case 0: list[i].x = (list[i].x & 0x0100) | data; break; + case 1: list[i].y = (data + 1) & 0xff; break; + case 2: list[i].character = data; break; + case 3: list[i].vflip = data & 0x80; + list[i].hflip = data & 0x40; + list[i].priority = (data >> 4) & 3; + list[i].palette = (data >> 1) & 7; + list[i].use_nameselect = data & 0x01; + break; + } + } else { + unsigned i = (addr & 0x1f) << 2; + list[i + 0].x = ((data & 0x01) << 8) | (list[i + 0].x & 0xff); + list[i + 0].size = data & 0x02; + list[i + 1].x = ((data & 0x04) << 6) | (list[i + 1].x & 0xff); + list[i + 1].size = data & 0x08; + list[i + 2].x = ((data & 0x10) << 4) | (list[i + 2].x & 0xff); + list[i + 2].size = data & 0x20; + list[i + 3].x = ((data & 0x40) << 2) | (list[i + 3].x & 0xff); + list[i + 3].size = data & 0x80; + list_valid = false; + } +} + +void PPU::Sprite::address_reset() { + self.regs.oam_addr = self.regs.oam_baseaddr << 1; + set_first(); +} + +void PPU::Sprite::set_first() { + regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127); +} + +bool PPU::Sprite::on_scanline(unsigned sprite) { + auto &s = list[sprite]; + if(s.x > 256 && (s.x + s.width - 1) < 512) return false; + signed height = (regs.interlace == false ? s.height : s.height >> 1); + if(self.vcounter() >= s.y && self.vcounter() < (s.y + height)) return true; + if((s.y + height) >= 256 && self.vcounter() < ((s.y + height) & 255)) return true; + return false; +} + +void PPU::Sprite::render() { + if(list_valid == false) { + list_valid = true; + for(unsigned i = 0; i < 128; i++) { + if(list[i].size == 0) { + static unsigned width[] = { 8, 8, 8, 16, 16, 32, 16, 16 }; + static unsigned height[] = { 8, 8, 8, 16, 16, 32, 32, 32 }; + list[i].width = width[regs.base_size]; + list[i].height = height[regs.base_size]; + } else { + static unsigned width[] = { 16, 32, 64, 32, 64, 64, 32, 32 }; + static unsigned height[] = { 16, 32, 64, 32, 64, 64, 64, 32 }; + list[i].width = width[regs.base_size]; + list[i].height = height[regs.base_size]; + if(regs.interlace && regs.base_size >= 6) list[i].height = 16; + } + } + } + + unsigned itemcount = 0; + unsigned tilecount = 0; + memset(output.priority, 0xff, 256); + memset(itemlist, 0xff, 32); + for(unsigned i = 0; i < 34; i++) tilelist[i].tile = 0xffff; + + for(unsigned i = 0; i < 128; i++) { + unsigned s = (regs.first_sprite + i) & 127; + if(on_scanline(s) == false) continue; + if(itemcount++ >= 32) break; + itemlist[itemcount - 1] = s; + } + + for(signed i = 31; i >= 0; i--) { + if(itemlist[i] == 0xff) continue; + auto &s = list[itemlist[i]]; + unsigned tile_width = s.width >> 3; + signed x = s.x; + signed y = (self.vcounter() - s.y) & 0xff; + if(regs.interlace) y <<= 1; + + if(s.vflip) { + if(s.width == s.height) { + y = (s.height - 1) - y; + } else { + y = (y < s.width) ? ((s.width - 1) - y) : (s.width + ((s.width - 1) - (y - s.width))); + } + } + + if(regs.interlace) { + y = (s.vflip == false) ? (y + self.field()) : (y - self.field()); + } + + x &= 511; + y &= 255; + + uint16 tdaddr = regs.tiledata_addr; + uint16 chrx = (s.character >> 0) & 15; + uint16 chry = (s.character >> 4) & 15; + if(s.use_nameselect) { + tdaddr += (256 * 32) + (regs.nameselect << 13); + } + chry += (y >> 3); + chry &= 15; + chry <<= 4; + + for(unsigned tx = 0; tx < tile_width; tx++) { + unsigned sx = (x + (tx << 3)) & 511; + if(x != 256 && sx >= 256 && (sx + 7) < 512) continue; + if(tilecount++ >= 34) break; + + unsigned n = tilecount - 1; + tilelist[n].x = sx; + tilelist[n].y = y; + tilelist[n].priority = s.priority; + tilelist[n].palette = 128 + (s.palette << 4); + tilelist[n].hflip = s.hflip; + + unsigned mx = (s.hflip == false) ? tx : ((tile_width - 1) - tx); + unsigned pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5); + tilelist[n].tile = (pos >> 5) & 0x07ff; + } + } + + regs.time_over |= (tilecount > 34); + regs.range_over |= (itemcount > 32); + + if(regs.main_enable == false && regs.sub_enable == false) return; + + for(unsigned i = 0; i < 34; i++) { + if(tilelist[i].tile == 0xffff) continue; + + auto &t = tilelist[i]; + uint8 *tiledata = self.cache.tile_4bpp(t.tile); + tiledata += (t.y & 7) << 3; + unsigned sx = t.x; + for(unsigned x = 0; x < 8; x++) { + sx &= 511; + if(sx < 256) { + unsigned color = *(tiledata + (t.hflip == false ? x : 7 - x)); + if(color) { + color += t.palette; + output.palette[sx] = color; + output.priority[sx] = t.priority; + } + } + sx++; + } + } + + if(regs.main_enable) window.render(0); + if(regs.sub_enable) window.render(1); + + unsigned priority0 = (priority0_enable ? regs.priority0 : 0); + unsigned priority1 = (priority1_enable ? regs.priority1 : 0); + unsigned priority2 = (priority2_enable ? regs.priority2 : 0); + unsigned priority3 = (priority3_enable ? regs.priority3 : 0); + if(priority0 + priority1 + priority2 + priority3 == 0) return; + const unsigned priority_table[] = { priority0, priority1, priority2, priority3 }; + + for(unsigned x = 0; x < 256; x++) { + if(output.priority[x] == 0xff) continue; + unsigned priority = priority_table[output.priority[x]]; + unsigned palette = output.palette[x]; + unsigned color = self.screen.get_palette(output.palette[x]); + if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, color, priority, 4 + (palette < 192)); + if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, color, priority, 4 + (palette < 192)); + } +} + +PPU::Sprite::Sprite(PPU &self) : self(self) { + priority0_enable = true; + priority1_enable = true; + priority2_enable = true; + priority3_enable = true; +} + +#endif diff --git a/snes/alt/ppu-performance/sprite/sprite.hpp b/snes/alt/ppu-performance/sprite/sprite.hpp new file mode 100755 index 00000000..06912d7e --- /dev/null +++ b/snes/alt/ppu-performance/sprite/sprite.hpp @@ -0,0 +1,71 @@ +class Sprite { + bool priority0_enable; + bool priority1_enable; + bool priority2_enable; + bool priority3_enable; + + struct Regs { + unsigned priority0; + unsigned priority1; + unsigned priority2; + unsigned priority3; + + unsigned base_size; + unsigned nameselect; + unsigned tiledata_addr; + unsigned first_sprite; + + bool main_enable; + bool sub_enable; + + bool interlace; + + bool time_over; + bool range_over; + } regs; + + struct List { + unsigned width; + unsigned height; + unsigned x; + unsigned y; + unsigned character; + bool use_nameselect; + bool vflip; + bool hflip; + unsigned palette; + unsigned priority; + bool size; + } list[128]; + bool list_valid; + + uint8 itemlist[32]; + struct TileList { + unsigned x; + unsigned y; + unsigned priority; + unsigned palette; + unsigned tile; + bool hflip; + } tilelist[34]; + + struct Output { + uint8 palette[256]; + uint8 priority[256]; + } output; + + LayerWindow window; + + void frame(); + void update_list(unsigned addr, uint8 data); + void address_reset(); + void set_first(); + alwaysinline bool on_scanline(unsigned sprite); + void render(); + + void serialize(serializer&); + Sprite(PPU &self); + + PPU &self; + friend class PPU; +}; diff --git a/snes/alt/ppu-performance/window/window.cpp b/snes/alt/ppu-performance/window/window.cpp new file mode 100755 index 00000000..216ee7b1 --- /dev/null +++ b/snes/alt/ppu-performance/window/window.cpp @@ -0,0 +1,98 @@ +#ifdef PPU_CPP + +void PPU::LayerWindow::render(bool screen) { + uint8 *output; + if(screen == 0) { + output = main; + if(main_enable == false) { + memset(output, 0, 256); + return; + } + } else { + output = sub; + if(sub_enable == false) { + memset(output, 0, 256); + return; + } + } + + if(one_enable == false && two_enable == false) { + memset(output, 0, 256); + return; + } + + if(one_enable == true && two_enable == false) { + bool set = 1 ^ one_invert, clr = !set; + for(unsigned x = 0; x < 256; x++) { + output[x] = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ? set : clr; + } + return; + } + + if(one_enable == false && two_enable == true) { + bool set = 1 ^ two_invert, clr = !set; + for(unsigned x = 0; x < 256; x++) { + output[x] = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ? set : clr; + } + return; + } + + for(unsigned x = 0; x < 256; x++) { + bool one_mask = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ^ one_invert; + bool two_mask = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ^ two_invert; + switch(mask) { + case 0: output[x] = one_mask | two_mask == 1; break; + case 1: output[x] = one_mask & two_mask == 1; break; + case 2: output[x] = one_mask ^ two_mask == 1; break; + case 3: output[x] = one_mask ^ two_mask == 0; break; + } + } +} + +// + +void PPU::ColorWindow::render(bool screen) { + uint8 *output = (screen == 0 ? main : sub); + bool set = 1, clr = 0; + + switch(screen == 0 ? main_mask : sub_mask) { + case 0: memset(output, 1, 256); return; //always + case 1: set = 1, clr = 0; break; //inside window only + case 2: set = 0, clr = 1; break; //outside window only + case 3: memset(output, 0, 256); return; //never + } + + if(one_enable == false && two_enable == false) { + memset(output, clr, 256); + return; + } + + if(one_enable == true && two_enable == false) { + if(one_invert) { set ^= 1; clr ^= 1; } + for(unsigned x = 0; x < 256; x++) { + output[x] = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ? set : clr; + } + return; + } + + if(one_enable == false && two_enable == true) { + if(two_invert) { set ^= 1; clr ^= 1; } + for(unsigned x = 0; x < 256; x++) { + output[x] = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ? set : clr; + } + return; + } + + for(unsigned x = 0; x < 256; x++) { + bool one_mask = (x >= ppu.regs.window_one_left && x <= ppu.regs.window_one_right) ^ one_invert; + bool two_mask = (x >= ppu.regs.window_two_left && x <= ppu.regs.window_two_right) ^ two_invert; + switch(mask) { + case 0: output[x] = one_mask | two_mask == 1 ? set : clr; break; + case 1: output[x] = one_mask & two_mask == 1 ? set : clr; break; + case 2: output[x] = one_mask ^ two_mask == 1 ? set : clr; break; + case 3: output[x] = one_mask ^ two_mask == 0 ? set : clr; break; + } + } +} + +#endif diff --git a/snes/alt/ppu-performance/window/window.hpp b/snes/alt/ppu-performance/window/window.hpp new file mode 100755 index 00000000..ee67dd5e --- /dev/null +++ b/snes/alt/ppu-performance/window/window.hpp @@ -0,0 +1,37 @@ +class LayerWindow { +public: + bool one_enable; + bool one_invert; + bool two_enable; + bool two_invert; + + unsigned mask; + + bool main_enable; + bool sub_enable; + + uint8 main[256]; + uint8 sub[256]; + + void render(bool screen); + void serialize(serializer&); +}; + +class ColorWindow { +public: + bool one_enable; + bool one_invert; + bool two_enable; + bool two_invert; + + unsigned mask; + + unsigned main_mask; + unsigned sub_mask; + + uint8 main[256]; + uint8 sub[256]; + + void render(bool screen); + void serialize(serializer&); +}; diff --git a/snes/alt/smp/algorithms.cpp b/snes/alt/smp/algorithms.cpp new file mode 100755 index 00000000..a55369fb --- /dev/null +++ b/snes/alt/smp/algorithms.cpp @@ -0,0 +1,122 @@ +uint8 SMP::op_adc(uint8 x, uint8 y) { + int r = x + y + regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = ~(x ^ y) & (x ^ r) & 0x80; + regs.p.h = (x ^ y ^ r) & 0x10; + regs.p.z = (uint8)r == 0; + regs.p.c = r > 0xff; + return r; +} + +uint16 SMP::op_addw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 0; + r = op_adc(x, y); + r |= op_adc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMP::op_and(uint8 x, uint8 y) { + x &= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_cmp(uint8 x, uint8 y) { + int r = x - y; + regs.p.n = r & 0x80; + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint16 SMP::op_cmpw(uint16 x, uint16 y) { + int r = x - y; + regs.p.n = r & 0x8000; + regs.p.z = (uint16)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint8 SMP::op_eor(uint8 x, uint8 y) { + x ^= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_or(uint8 x, uint8 y) { + x |= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_sbc(uint8 x, uint8 y) { + int r = x - y - !regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = (x ^ y) & (x ^ r) & 0x80; + regs.p.h = !((x ^ y ^ r) & 0x10); + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return r; +} + +uint16 SMP::op_subw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 1; + r = op_sbc(x, y); + r |= op_sbc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMP::op_inc(uint8 x) { + x++; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_dec(uint8 x) { + x--; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_asl(uint8 x) { + regs.p.c = x & 0x80; + x <<= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_lsr(uint8 x) { + regs.p.c = x & 0x01; + x >>= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_rol(uint8 x) { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = x & 0x80; + x = (x << 1) | carry; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_ror(uint8 x) { + unsigned carry = (unsigned)regs.p.c << 7; + regs.p.c = x & 0x01; + x = carry | (x >> 1); + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} diff --git a/snes/alt/smp/core.cpp b/snes/alt/smp/core.cpp new file mode 100755 index 00000000..21bf5bf2 --- /dev/null +++ b/snes/alt/smp/core.cpp @@ -0,0 +1,104 @@ +void SMP::tick() { + timer0.tick(); + timer1.tick(); + timer2.tick(); + + clock += cycle_step_cpu; + dsp.clock -= 24; + synchronize_dsp(); +} + +void SMP::op_io() { + #if defined(CYCLE_ACCURATE) + tick(); + #endif +} + +uint8 SMP::op_read(uint16 addr) { + #if defined(CYCLE_ACCURATE) + tick(); + #endif + if((addr & 0xfff0) == 0x00f0) return mmio_read(addr); + if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; + return apuram[addr]; +} + +void SMP::op_write(uint16 addr, uint8 data) { + #if defined(CYCLE_ACCURATE) + tick(); + #endif + if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data); + apuram[addr] = data; //all writes go to RAM, even MMIO writes +} + +void SMP::op_step() { + #define op_readpc() op_read(regs.pc++) + #define op_readdp(addr) op_read((regs.p.p << 8) + addr) + #define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data) + #define op_readaddr(addr) op_read(addr) + #define op_writeaddr(addr, data) op_write(addr, data) + #define op_readstack() op_read(0x0100 | ++regs.sp) + #define op_writestack(data) op_write(0x0100 | regs.sp--, data) + + #if defined(CYCLE_ACCURATE) + + if(opcode_cycle == 0) { + opcode_number = op_readpc(); + opcode_cycle++; + } else switch(opcode_number) { + #include "core/opcycle_misc.cpp" + #include "core/opcycle_mov.cpp" + #include "core/opcycle_pc.cpp" + #include "core/opcycle_read.cpp" + #include "core/opcycle_rmw.cpp" + } + + #else + + unsigned opcode = op_readpc(); + switch(opcode) { + #include "core/op_misc.cpp" + #include "core/op_mov.cpp" + #include "core/op_pc.cpp" + #include "core/op_read.cpp" + #include "core/op_rmw.cpp" + } + + //TODO: untaken branches should consume less cycles + + timer0.tick(cycle_count_table[opcode]); + timer1.tick(cycle_count_table[opcode]); + timer2.tick(cycle_count_table[opcode]); + + clock += cycle_table_cpu[opcode]; + dsp.clock -= cycle_table_dsp[opcode]; + synchronize_dsp(); + + #endif +} + +const unsigned SMP::cycle_count_table[256] = { + #define c 12 +//0 1 2 3 4 5 6 7 8 9 A B C D E F + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0 + 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,4,6, //1 + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,7,4, //2 + 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,3,8, //3 + + 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,6,6, //4 + 4,8,4,7, 4,5,5,6, 5,5,4,5, 2,2,4,3, //5 + 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,7,5, //6 + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,6, //7 + + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,2,4,5, //8 + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,c,5, //9 + 3,8,4,7, 3,4,3,6, 2,6,4,4, 5,2,4,4, //A + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,4, //B + + 3,8,4,7, 4,5,4,7, 2,5,6,4, 5,2,4,9, //C + 4,8,4,7, 5,6,6,7, 4,5,5,5, 2,2,8,3, //D + 2,8,4,7, 3,4,3,6, 2,4,5,3, 4,3,4,1, //E + 4,8,4,7, 4,5,5,6, 3,4,5,4, 2,2,6,1, //F + + #undef c +}; diff --git a/snes/alt/smp/core/cc.sh b/snes/alt/smp/core/cc.sh new file mode 100755 index 00000000..937b7139 --- /dev/null +++ b/snes/alt/smp/core/cc.sh @@ -0,0 +1 @@ +g++-4.5 -std=gnu++0x -I../../../.. -o generate generate.cpp diff --git a/snes/alt/smp/core/generate.cpp b/snes/alt/smp/core/generate.cpp new file mode 100755 index 00000000..77ab3ed2 --- /dev/null +++ b/snes/alt/smp/core/generate.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +using namespace nall; + +static bool cycle_accurate; + +struct opcode_t { + string name; + lstring args; + unsigned opcode; +}; + +void generate(const char *sourceFilename, const char *targetFilename) { + file fp; + fp.open(targetFilename, file::mode::write); + + string filedata; + filedata.readfile(sourceFilename); + filedata.replace("\r", ""); + + lstring block; + block.split("\n\n", filedata); + + foreach(data, block) { + lstring lines; + lines.split("\n", data); + + linear_vector array; + + unsigned sourceStart = 0; + foreach(line, lines, currentLine) { + line.transform("()", "``"); + lstring part; + part.split("`", line); + lstring arguments; + arguments.split(", ", part[1]); + + opcode_t opcode; + opcode.name = part[0]; + opcode.args = arguments; + opcode.opcode = hex(arguments[0]); + array.append(opcode); + + line.rtrim<1>(","); + if(line.endswith(" {")) { + line.rtrim<1>("{ "); + sourceStart = currentLine + 1; + break; + } + } + + if(cycle_accurate == false) { + foreach(opcode, array) { + fp.print("case 0x", hex<2>(opcode.opcode), ": {\n"); + + for(unsigned n = sourceStart; n < lines.size(); n++) { + if(lines[n] == "}") break; + + string output; + + if(lines[n].beginswith(" ")) { + output = lines[n]; + } else { + lstring part; + part.split<1>(":", lines[n]); + output = { " ", part[1] }; + } + + output.replace("$1", opcode.args[1]); + output.replace("$2", opcode.args[2]); + output.replace("$3", opcode.args[3]); + output.replace("$4", opcode.args[4]); + output.replace("$5", opcode.args[5]); + output.replace("$6", opcode.args[6]); + output.replace("$7", opcode.args[7]); + output.replace("$8", opcode.args[8]); + output.replace("end;", "break;"); + + fp.print(output, "\n"); + } + + fp.print(" break;\n"); + fp.print("}\n\n"); + } + } else { + foreach(opcode, array) { + fp.print("case 0x", hex<2>(opcode.opcode), ": {\n"); + fp.print(" switch(opcode_cycle++) {\n"); + + for(unsigned n = sourceStart; n < lines.size(); n++) { + if(lines[n] == "}") break; + + bool nextLineEndsCycle = false; + if(lines[n + 1] == "}") nextLineEndsCycle = true; + if(lines[n + 1].beginswith(" ") == false) nextLineEndsCycle = true; + + string output; + + if(lines[n].beginswith(" ")) { + output = { " ", lines[n] }; + } else { + lstring part; + part.split<1>(":", lines[n]); + fp.print(" case ", (unsigned)decimal(part[0]), ":\n"); + output = { " ", part[1] }; + } + + output.replace("$1", opcode.args[1]); + output.replace("$2", opcode.args[2]); + output.replace("$3", opcode.args[3]); + output.replace("$4", opcode.args[4]); + output.replace("$5", opcode.args[5]); + output.replace("$6", opcode.args[6]); + output.replace("$7", opcode.args[7]); + output.replace("$8", opcode.args[8]); + output.replace("end;", "{ opcode_cycle = 0; break; }"); + + fp.print(output, "\n"); + if(nextLineEndsCycle) { + if(lines[n + 1].beginswith("}")) { + fp.print(" opcode_cycle = 0;\n"); + } + fp.print(" break;\n"); + } + } + + fp.print(" }\n"); + fp.print(" break;\n"); + fp.print("}\n\n"); + } + } + } + + fp.close(); +} + +int main() { + cycle_accurate = false; + generate("op_misc.b", "op_misc.cpp"); + generate("op_mov.b", "op_mov.cpp" ); + generate("op_pc.b", "op_pc.cpp" ); + generate("op_read.b", "op_read.cpp"); + generate("op_rmw.b", "op_rmw.cpp" ); + + cycle_accurate = true; + generate("op_misc.b", "opcycle_misc.cpp"); + generate("op_mov.b", "opcycle_mov.cpp" ); + generate("op_pc.b", "opcycle_pc.cpp" ); + generate("op_read.b", "opcycle_read.cpp"); + generate("op_rmw.b", "opcycle_rmw.cpp" ); + + return 0; +} diff --git a/snes/alt/smp/core/op_misc.b b/snes/alt/smp/core/op_misc.b new file mode 100755 index 00000000..fb258650 --- /dev/null +++ b/snes/alt/smp/core/op_misc.b @@ -0,0 +1,163 @@ +nop(0x00) { +1:op_io(); +} + +sleep(0xef), +stop(0xff) { +1:op_io(); +2:op_io(); + regs.pc--; +} + +xcn(0x9f) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +daa(0xdf) { +1:op_io(); +2:op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +das(0xbe) { +1:op_io(); +2:op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +clrc(0x60, regs.p.c = 0), +clrp(0x20, regs.p.p = 0), +setc(0x80, regs.p.c = 1), +setp(0x40, regs.p.p = 1) { +1:op_io(); + $1; +} + +clrv(0xe0) { +1:op_io(); + regs.p.v = 0; + regs.p.h = 0; +} + +notc(0xed) { +1:op_io(); +2:op_io(); + regs.p.c = !regs.p.c; +} + +ei(0xa0, 1), +di(0xc0, 0) { +1:op_io(); +2:op_io(); + regs.p.i = $1; +} + +set0_dp(0x02, rd |= 0x01), +clr0_dp(0x12, rd &= ~0x01), +set1_dp(0x22, rd |= 0x02), +clr1_dp(0x32, rd &= ~0x02), +set2_dp(0x42, rd |= 0x04), +clr2_dp(0x52, rd &= ~0x04), +set3_dp(0x62, rd |= 0x08), +clr3_dp(0x72, rd &= ~0x08), +set4_dp(0x82, rd |= 0x10), +clr4_dp(0x92, rd &= ~0x10), +set5_dp(0xa2, rd |= 0x20), +clr5_dp(0xb2, rd &= ~0x20), +set6_dp(0xc2, rd |= 0x40), +clr6_dp(0xd2, rd &= ~0x40), +set7_dp(0xe2, rd |= 0x80), +clr7_dp(0xf2, rd &= ~0x80) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:$1; + op_writedp(dp, rd); +} + +push_a(0x2d, a), +push_x(0x4d, x), +push_y(0x6d, y), +push_p(0x0d, p) { +1:op_io(); +2:op_io(); +3:op_writestack(regs.$1); +} + +pop_a(0xae, a), +pop_x(0xce, x), +pop_y(0xee, y), +pop_p(0x8e, p) { +1:op_io(); +2:op_io(); +3:regs.$1 = op_readstack(); +} + +mul_ya(0xcf) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); +5:op_io(); +6:op_io(); +7:op_io(); +8:op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} + +div_ya_x(0x9e) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); +5:op_io(); +6:op_io(); +7:op_io(); +8:op_io(); +9:op_io(); +10:op_io(); +11:op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} diff --git a/snes/alt/smp/core/op_misc.cpp b/snes/alt/smp/core/op_misc.cpp new file mode 100755 index 00000000..9a6a062d --- /dev/null +++ b/snes/alt/smp/core/op_misc.cpp @@ -0,0 +1,346 @@ +case 0x00: { + op_io(); + break; +} + +case 0xef: { + op_io(); + op_io(); + regs.pc--; + break; +} + +case 0xff: { + op_io(); + op_io(); + regs.pc--; + break; +} + +case 0x9f: { + op_io(); + op_io(); + op_io(); + op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xdf: { + op_io(); + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xbe: { + op_io(); + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0x60: { + op_io(); + regs.p.c = 0; + break; +} + +case 0x20: { + op_io(); + regs.p.p = 0; + break; +} + +case 0x80: { + op_io(); + regs.p.c = 1; + break; +} + +case 0x40: { + op_io(); + regs.p.p = 1; + break; +} + +case 0xe0: { + op_io(); + regs.p.v = 0; + regs.p.h = 0; + break; +} + +case 0xed: { + op_io(); + op_io(); + regs.p.c = !regs.p.c; + break; +} + +case 0xa0: { + op_io(); + op_io(); + regs.p.i = 1; + break; +} + +case 0xc0: { + op_io(); + op_io(); + regs.p.i = 0; + break; +} + +case 0x02: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x01; + op_writedp(dp, rd); + break; +} + +case 0x12: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x01; + op_writedp(dp, rd); + break; +} + +case 0x22: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x02; + op_writedp(dp, rd); + break; +} + +case 0x32: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x02; + op_writedp(dp, rd); + break; +} + +case 0x42: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x04; + op_writedp(dp, rd); + break; +} + +case 0x52: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x04; + op_writedp(dp, rd); + break; +} + +case 0x62: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x08; + op_writedp(dp, rd); + break; +} + +case 0x72: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x08; + op_writedp(dp, rd); + break; +} + +case 0x82: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x10; + op_writedp(dp, rd); + break; +} + +case 0x92: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x10; + op_writedp(dp, rd); + break; +} + +case 0xa2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x20; + op_writedp(dp, rd); + break; +} + +case 0xb2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x20; + op_writedp(dp, rd); + break; +} + +case 0xc2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x40; + op_writedp(dp, rd); + break; +} + +case 0xd2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x40; + op_writedp(dp, rd); + break; +} + +case 0xe2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x80; + op_writedp(dp, rd); + break; +} + +case 0xf2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x80; + op_writedp(dp, rd); + break; +} + +case 0x2d: { + op_io(); + op_io(); + op_writestack(regs.a); + break; +} + +case 0x4d: { + op_io(); + op_io(); + op_writestack(regs.x); + break; +} + +case 0x6d: { + op_io(); + op_io(); + op_writestack(regs.y); + break; +} + +case 0x0d: { + op_io(); + op_io(); + op_writestack(regs.p); + break; +} + +case 0xae: { + op_io(); + op_io(); + regs.a = op_readstack(); + break; +} + +case 0xce: { + op_io(); + op_io(); + regs.x = op_readstack(); + break; +} + +case 0xee: { + op_io(); + op_io(); + regs.y = op_readstack(); + break; +} + +case 0x8e: { + op_io(); + op_io(); + regs.p = op_readstack(); + break; +} + +case 0xcf: { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0x9e: { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + diff --git a/snes/alt/smp/core/op_mov.b b/snes/alt/smp/core/op_mov.b new file mode 100755 index 00000000..dee821af --- /dev/null +++ b/snes/alt/smp/core/op_mov.b @@ -0,0 +1,217 @@ +mov_a_x(0x7d, a, x), +mov_a_y(0xdd, a, y), +mov_x_a(0x5d, x, a), +mov_y_a(0xfd, y, a), +mov_x_sp(0x9d, x, sp) { +1:op_io(); + regs.$1 = regs.$2; + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_sp_x(0xbd, sp, x) { +1:op_io(); + regs.$1 = regs.$2; +} + +mov_a_const(0xe8, a), +mov_x_const(0xcd, x), +mov_y_const(0x8d, y) { +1:regs.$1 = op_readpc(); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_ix(0xe6) { +1:op_io(); +2:regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_ixinc(0xbf) { +1:op_io(); +2:regs.a = op_readdp(regs.x++); +3:op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_dp(0xe4, a), +mov_x_dp(0xf8, x), +mov_y_dp(0xeb, y) { +1:sp = op_readpc(); +2:regs.$1 = op_readdp(sp); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_dpx(0xf4, a, x), +mov_x_dpy(0xf9, x, y), +mov_y_dpx(0xfb, y, x) { +1:sp = op_readpc(); +2:op_io(); +3:regs.$1 = op_readdp(sp + regs.$2); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_addr(0xe5, a), +mov_x_addr(0xe9, x), +mov_y_addr(0xec, y) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:regs.$1 = op_readaddr(sp); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_addrx(0xf5, x), +mov_a_addry(0xf6, y) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:op_io(); +4:regs.a = op_readaddr(sp + regs.$1); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_idpx(0xe7) { +1:dp = op_readpc() + regs.x; +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_idpy(0xf7) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_dp_dp(0xfa) { +1:sp = op_readpc(); +2:rd = op_readdp(sp); +3:dp = op_readpc(); +4:op_writedp(dp, rd); +} + +mov_dp_const(0x8f) { +1:rd = op_readpc(); +2:dp = op_readpc(); +3:op_readdp(dp); +4:op_writedp(dp, rd); +} + +mov_ix_a(0xc6) { +1:op_io(); +2:op_readdp(regs.x); +3:op_writedp(regs.x, regs.a); +} + +mov_ixinc_a(0xaf) { +1:op_io(); +2:op_io(); +3:op_writedp(regs.x++, regs.a); +} + +mov_dp_a(0xc4, a), +mov_dp_x(0xd8, x), +mov_dp_y(0xcb, y) { +1:dp = op_readpc(); +2:op_readdp(dp); +3:op_writedp(dp, regs.$1); +} + +mov_dpx_a(0xd4, x, a), +mov_dpy_x(0xd9, y, x), +mov_dpx_y(0xdb, x, y) { +1:dp = op_readpc(); +2:op_io(); + dp += regs.$1; +3:op_readdp(dp); +4:op_writedp(dp, regs.$2); +} + +mov_addr_a(0xc5, a), +mov_addr_x(0xc9, x), +mov_addr_y(0xcc, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_readaddr(dp); +4:op_writeaddr(dp, regs.$1); +} + +mov_addrx_a(0xd5, x), +mov_addry_a(0xd6, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); + dp += regs.$1; +4:op_readaddr(dp); +5:op_writeaddr(dp, regs.a); +} + +mov_idpx_a(0xc7) { +1:sp = op_readpc(); +2:op_io(); + sp += regs.x; +3:dp = op_readdp(sp); +4:dp |= op_readdp(sp + 1) << 8; +5:op_readaddr(dp); +6:op_writeaddr(dp, regs.a); +} + +mov_idpy_a(0xd7) { +1:sp = op_readpc(); +2:dp = op_readdp(sp); +3:dp |= op_readdp(sp + 1) << 8; +4:op_io(); + dp += regs.y; +5:op_readaddr(dp); +6:op_writeaddr(dp, regs.a); +} + +movw_ya_dp(0xba) { +1:sp = op_readpc(); +2:regs.a = op_readdp(sp); +3:op_io(); +4:regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); +} + +movw_dp_ya(0xda) { +1:dp = op_readpc(); +2:op_readdp(dp); +3:op_writedp(dp, regs.a); +4:op_writedp(dp + 1, regs.y); +} + +mov1_c_bit(0xaa) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); +} + +mov1_bit_c(0xca) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); +4:op_io(); +5:op_writeaddr(dp, rd); +} diff --git a/snes/alt/smp/core/op_mov.cpp b/snes/alt/smp/core/op_mov.cpp new file mode 100755 index 00000000..f3079423 --- /dev/null +++ b/snes/alt/smp/core/op_mov.cpp @@ -0,0 +1,389 @@ +case 0x7d: { + op_io(); + regs.a = regs.x; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xdd: { + op_io(); + regs.a = regs.y; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0x5d: { + op_io(); + regs.x = regs.a; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xfd: { + op_io(); + regs.y = regs.a; + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0x9d: { + op_io(); + regs.x = regs.sp; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xbd: { + op_io(); + regs.sp = regs.x; + break; +} + +case 0xe8: { + regs.a = op_readpc(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xcd: { + regs.x = op_readpc(); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0x8d: { + regs.y = op_readpc(); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xe6: { + op_io(); + regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xbf: { + op_io(); + regs.a = op_readdp(regs.x++); + op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe4: { + sp = op_readpc(); + regs.a = op_readdp(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf8: { + sp = op_readpc(); + regs.x = op_readdp(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xeb: { + sp = op_readpc(); + regs.y = op_readdp(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xf4: { + sp = op_readpc(); + op_io(); + regs.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf9: { + sp = op_readpc(); + op_io(); + regs.x = op_readdp(sp + regs.y); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xfb: { + sp = op_readpc(); + op_io(); + regs.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xe5: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe9: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.x = op_readaddr(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xec: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.y = op_readaddr(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xf5: { + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + regs.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf6: { + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xfa: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + op_writedp(dp, rd); + break; +} + +case 0x8f: { + rd = op_readpc(); + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, rd); + break; +} + +case 0xc6: { + op_io(); + op_readdp(regs.x); + op_writedp(regs.x, regs.a); + break; +} + +case 0xaf: { + op_io(); + op_io(); + op_writedp(regs.x++, regs.a); + break; +} + +case 0xc4: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.a); + break; +} + +case 0xd8: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.x); + break; +} + +case 0xcb: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.y); + break; +} + +case 0xd4: { + dp = op_readpc(); + op_io(); + dp += regs.x; + op_readdp(dp); + op_writedp(dp, regs.a); + break; +} + +case 0xd9: { + dp = op_readpc(); + op_io(); + dp += regs.y; + op_readdp(dp); + op_writedp(dp, regs.x); + break; +} + +case 0xdb: { + dp = op_readpc(); + op_io(); + dp += regs.x; + op_readdp(dp); + op_writedp(dp, regs.y); + break; +} + +case 0xc5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xc9: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.x); + break; +} + +case 0xcc: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.y); + break; +} + +case 0xd5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xd6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.y; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xc7: { + sp = op_readpc(); + op_io(); + sp += regs.x; + dp = op_readdp(sp); + dp |= op_readdp(sp + 1) << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xd7: { + sp = op_readpc(); + dp = op_readdp(sp); + dp |= op_readdp(sp + 1) << 8; + op_io(); + dp += regs.y; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xba: { + sp = op_readpc(); + regs.a = op_readdp(sp); + op_io(); + regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); + break; +} + +case 0xda: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.a); + op_writedp(dp + 1, regs.y); + break; +} + +case 0xaa: { + sp = op_readpc(); + sp |= op_readpc() << 8; + bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); + break; +} + +case 0xca: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); + op_io(); + op_writeaddr(dp, rd); + break; +} + diff --git a/snes/alt/smp/core/op_pc.b b/snes/alt/smp/core/op_pc.b new file mode 100755 index 00000000..affaf844 --- /dev/null +++ b/snes/alt/smp/core/op_pc.b @@ -0,0 +1,179 @@ +bra(0x2f, 0), +beq(0xf0, !regs.p.z), +bne(0xd0, regs.p.z), +bcs(0xb0, !regs.p.c), +bcc(0x90, regs.p.c), +bvs(0x70, !regs.p.v), +bvc(0x50, regs.p.v), +bmi(0x30, !regs.p.n), +bpl(0x10, regs.p.n) { +1:rd = op_readpc(); + if($1)end; +2:op_io(); +3:op_io(); + regs.pc += (int8)rd; +} + +bbs0(0x03, 0x01, !=), +bbc0(0x13, 0x01, ==), +bbs1(0x23, 0x02, !=), +bbc1(0x33, 0x02, ==), +bbs2(0x43, 0x04, !=), +bbc2(0x53, 0x04, ==), +bbs3(0x63, 0x08, !=), +bbc3(0x73, 0x08, ==), +bbs4(0x83, 0x10, !=), +bbc4(0x93, 0x10, ==), +bbs5(0xa3, 0x20, !=), +bbc5(0xb3, 0x20, ==), +bbs6(0xc3, 0x40, !=), +bbc6(0xd3, 0x40, ==), +bbs7(0xe3, 0x80, !=), +bbc7(0xf3, 0x80, ==) { +1:dp = op_readpc(); +2:sp = op_readdp(dp); +3:rd = op_readpc(); +4:op_io(); + if((sp & $1) $2 $1)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +cbne_dp(0x2e) { +1:dp = op_readpc(); +2:sp = op_readdp(dp); +3:rd = op_readpc(); +4:op_io(); + if(regs.a == sp)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +cbne_dpx(0xde) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp + regs.x); +4:rd = op_readpc(); +5:op_io(); + if(regs.a == sp)end; +6:op_io(); +7:op_io(); + regs.pc += (int8)rd; +} + +dbnz_dp(0x6e) { +1:dp = op_readpc(); +2:wr = op_readdp(dp); +3:op_writedp(dp, --wr); +4:rd = op_readpc(); + if(wr == 0x00)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +dbnz_y(0xfe) { +1:rd = op_readpc(); +2:op_io(); + regs.y--; +3:op_io(); + if(regs.y == 0x00)end; +4:op_io(); +5:op_io(); + regs.pc += (int8)rd; +} + +jmp_addr(0x5f) { +1:rd = op_readpc(); +2:rd |= op_readpc() << 8; + regs.pc = rd; +} + +jmp_iaddrx(0x1f) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); + dp += regs.x; +4:rd = op_readaddr(dp); +5:rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; +} + +call(0x3f) { +1:rd = op_readpc(); +2:rd |= op_readpc() << 8; +3:op_io(); +4:op_io(); +5:op_io(); +6:op_writestack(regs.pc >> 8); +7:op_writestack(regs.pc); + regs.pc = rd; +} + +pcall(0x4f) { +1:rd = op_readpc(); +2:op_io(); +3:op_io(); +4:op_writestack(regs.pc >> 8); +5:op_writestack(regs.pc); + regs.pc = 0xff00 | rd; +} + +tcall_0(0x01, 0), +tcall_1(0x11, 1), +tcall_2(0x21, 2), +tcall_3(0x31, 3), +tcall_4(0x41, 4), +tcall_5(0x51, 5), +tcall_6(0x61, 6), +tcall_7(0x71, 7), +tcall_8(0x81, 8), +tcall_9(0x91, 9), +tcall_10(0xa1, 10), +tcall_11(0xb1, 11), +tcall_12(0xc1, 12), +tcall_13(0xd1, 13), +tcall_14(0xe1, 14), +tcall_15(0xf1, 15) { +1:dp = 0xffde - ($1 << 1); + rd = op_readaddr(dp); +2:rd |= op_readaddr(dp + 1) << 8; +3:op_io(); +4:op_io(); +5:op_io(); +6:op_writestack(regs.pc >> 8); +7:op_writestack(regs.pc); + regs.pc = rd; +} + +brk(0x0f) { +1:rd = op_readaddr(0xffde); +2:rd |= op_readaddr(0xffdf) << 8; +3:op_io(); +4:op_io(); +5:op_writestack(regs.pc >> 8); +6:op_writestack(regs.pc); +7:op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; +} + +ret(0x6f) { +1:rd = op_readstack(); +2:rd |= op_readstack() << 8; +3:op_io(); +4:op_io(); + regs.pc = rd; +} + +reti(0x7f) { +1:regs.p = op_readstack(); +2:rd = op_readstack(); +3:rd |= op_readstack() << 8; +4:op_io(); +5:op_io(); + regs.pc = rd; +} diff --git a/snes/alt/smp/core/op_pc.cpp b/snes/alt/smp/core/op_pc.cpp new file mode 100755 index 00000000..763a033e --- /dev/null +++ b/snes/alt/smp/core/op_pc.cpp @@ -0,0 +1,603 @@ +case 0x2f: { + rd = op_readpc(); + if(0)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xf0: { + rd = op_readpc(); + if(!regs.p.z)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xd0: { + rd = op_readpc(); + if(regs.p.z)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xb0: { + rd = op_readpc(); + if(!regs.p.c)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x90: { + rd = op_readpc(); + if(regs.p.c)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x70: { + rd = op_readpc(); + if(!regs.p.v)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x50: { + rd = op_readpc(); + if(regs.p.v)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x30: { + rd = op_readpc(); + if(!regs.p.n)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x10: { + rd = op_readpc(); + if(regs.p.n)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x03: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x01) != 0x01)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x13: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x01) == 0x01)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x23: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x02) != 0x02)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x33: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x02) == 0x02)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x43: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x04) != 0x04)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x53: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x04) == 0x04)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x63: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x08) != 0x08)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x73: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x08) == 0x08)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x83: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x10) != 0x10)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x93: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x10) == 0x10)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xa3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x20) != 0x20)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xb3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x20) == 0x20)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xc3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x40) != 0x40)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xd3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x40) == 0x40)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xe3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x80) != 0x80)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xf3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x80) == 0x80)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x2e: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if(regs.a == sp)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xde: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + regs.x); + rd = op_readpc(); + op_io(); + if(regs.a == sp)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x6e: { + dp = op_readpc(); + wr = op_readdp(dp); + op_writedp(dp, --wr); + rd = op_readpc(); + if(wr == 0x00)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xfe: { + rd = op_readpc(); + op_io(); + regs.y--; + op_io(); + if(regs.y == 0x00)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x5f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + regs.pc = rd; + break; +} + +case 0x1f: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; + break; +} + +case 0x3f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x4f: { + rd = op_readpc(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = 0xff00 | rd; + break; +} + +case 0x01: { + dp = 0xffde - (0 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x11: { + dp = 0xffde - (1 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x21: { + dp = 0xffde - (2 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x31: { + dp = 0xffde - (3 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x41: { + dp = 0xffde - (4 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x51: { + dp = 0xffde - (5 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x61: { + dp = 0xffde - (6 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x71: { + dp = 0xffde - (7 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x81: { + dp = 0xffde - (8 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x91: { + dp = 0xffde - (9 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xa1: { + dp = 0xffde - (10 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xb1: { + dp = 0xffde - (11 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xc1: { + dp = 0xffde - (12 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xd1: { + dp = 0xffde - (13 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xe1: { + dp = 0xffde - (14 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xf1: { + dp = 0xffde - (15 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x0f: { + rd = op_readaddr(0xffde); + rd |= op_readaddr(0xffdf) << 8; + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; + break; +} + +case 0x6f: { + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(); + op_io(); + regs.pc = rd; + break; +} + +case 0x7f: { + regs.p = op_readstack(); + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(); + op_io(); + regs.pc = rd; + break; +} + diff --git a/snes/alt/smp/core/op_read.b b/snes/alt/smp/core/op_read.b new file mode 100755 index 00000000..fd2f9d82 --- /dev/null +++ b/snes/alt/smp/core/op_read.b @@ -0,0 +1,205 @@ +adc_a_const(0x88, adc, a), +and_a_const(0x28, and, a), +cmp_a_const(0x68, cmp, a), +cmp_x_const(0xc8, cmp, x), +cmp_y_const(0xad, cmp, y), +eor_a_const(0x48, eor, a), +or_a_const(0x08, or, a), +sbc_a_const(0xa8, sbc, a) { +1:rd = op_readpc(); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_ix(0x86, adc), +and_a_ix(0x26, and), +cmp_a_ix(0x66, cmp), +eor_a_ix(0x46, eor), +or_a_ix(0x06, or), +sbc_a_ix(0xa6, sbc) { +1:op_io(); +2:rd = op_readdp(regs.x); + regs.a = op_$1(regs.a, rd); +} + +adc_a_dp(0x84, adc, a), +and_a_dp(0x24, and, a), +cmp_a_dp(0x64, cmp, a), +cmp_x_dp(0x3e, cmp, x), +cmp_y_dp(0x7e, cmp, y), +eor_a_dp(0x44, eor, a), +or_a_dp(0x04, or, a), +sbc_a_dp(0xa4, sbc, a) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_dpx(0x94, adc), +and_a_dpx(0x34, and), +cmp_a_dpx(0x74, cmp), +eor_a_dpx(0x54, eor), +or_a_dpx(0x14, or), +sbc_a_dpx(0xb4, sbc) { +1:dp = op_readpc(); +2:op_io(); +3:rd = op_readdp(dp + regs.x); + regs.a = op_$1(regs.a, rd); +} + +adc_a_addr(0x85, adc, a), +and_a_addr(0x25, and, a), +cmp_a_addr(0x65, cmp, a), +cmp_x_addr(0x1e, cmp, x), +cmp_y_addr(0x5e, cmp, y), +eor_a_addr(0x45, eor, a), +or_a_addr(0x05, or, a), +sbc_a_addr(0xa5, sbc, a) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_addrx(0x95, adc, x), +adc_a_addry(0x96, adc, y), +and_a_addrx(0x35, and, x), +and_a_addry(0x36, and, y), +cmp_a_addrx(0x75, cmp, x), +cmp_a_addry(0x76, cmp, y), +eor_a_addrx(0x55, eor, x), +eor_a_addry(0x56, eor, y), +or_a_addrx(0x15, or, x), +or_a_addry(0x16, or, y), +sbc_a_addrx(0xb5, sbc, x), +sbc_a_addry(0xb6, sbc, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); +4:rd = op_readaddr(dp + regs.$2); + regs.a = op_$1(regs.a, rd); +} + +adc_a_idpx(0x87, adc), +and_a_idpx(0x27, and), +cmp_a_idpx(0x67, cmp), +eor_a_idpx(0x47, eor), +or_a_idpx(0x07, or), +sbc_a_idpx(0xa7, sbc) { +1:dp = op_readpc() + regs.x; +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:rd = op_readaddr(sp); + regs.a = op_$1(regs.a, rd); +} + +adc_a_idpy(0x97, adc), +and_a_idpy(0x37, and), +cmp_a_idpy(0x77, cmp), +eor_a_idpy(0x57, eor), +or_a_idpy(0x17, or), +sbc_a_idpy(0xb7, sbc) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:rd = op_readaddr(sp + regs.y); + regs.a = op_$1(regs.a, rd); +} + +adc_ix_iy(0x99, adc, 1), +and_ix_iy(0x39, and, 1), +cmp_ix_iy(0x79, cmp, 0), +eor_ix_iy(0x59, eor, 1), +or_ix_iy(0x19, or, 1), +sbc_ix_iy(0xb9, sbc, 1) { +1:op_io(); +2:rd = op_readdp(regs.y); +3:wr = op_readdp(regs.x); + wr = op_$1(wr, rd); +4:($2) ? op_writedp(regs.x, wr) : op_io(); +} + +adc_dp_dp(0x89, adc, 1), +and_dp_dp(0x29, and, 1), +cmp_dp_dp(0x69, cmp, 0), +eor_dp_dp(0x49, eor, 1), +or_dp_dp(0x09, or, 1), +sbc_dp_dp(0xa9, sbc, 1) { +1:sp = op_readpc(); +2:rd = op_readdp(sp); +3:dp = op_readpc(); +4:wr = op_readdp(dp); +5:wr = op_$1(wr, rd); + ($2) ? op_writedp(dp, wr) : op_io(); +} + +adc_dp_const(0x98, adc, 1), +and_dp_const(0x38, and, 1), +cmp_dp_const(0x78, cmp, 0), +eor_dp_const(0x58, eor, 1), +or_dp_const(0x18, or, 1), +sbc_dp_const(0xb8, sbc, 1) { +1:rd = op_readpc(); +2:dp = op_readpc(); +3:wr = op_readdp(dp); +4:wr = op_$1(wr, rd); + ($2) ? op_writedp(dp, wr) : op_io(); +} + +addw_ya_dp(0x7a, addw), +subw_ya_dp(0x9a, subw) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:op_io(); +4:rd |= op_readdp(dp + 1) << 8; + regs.ya = op_$1(regs.ya, rd); +} + +cmpw_ya_dp(0x5a) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); +} + +and1_bit(0x4a, !!), +and1_notbit(0x6a, !) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & $1(rd & (1 << bit)); +} + +eor1_bit(0x8a) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); +4:op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); +} + +not1_bit(0xea) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); +4:op_writeaddr(dp, rd); +} + +or1_bit(0x0a, !!), +or1_notbit(0x2a, !) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); +4:op_io(); + regs.p.c = regs.p.c | $1(rd & (1 << bit)); +} diff --git a/snes/alt/smp/core/op_read.cpp b/snes/alt/smp/core/op_read.cpp new file mode 100755 index 00000000..2a16a3c8 --- /dev/null +++ b/snes/alt/smp/core/op_read.cpp @@ -0,0 +1,744 @@ +case 0x88: { + rd = op_readpc(); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x28: { + rd = op_readpc(); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x68: { + rd = op_readpc(); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0xc8: { + rd = op_readpc(); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0xad: { + rd = op_readpc(); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x48: { + rd = op_readpc(); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x08: { + rd = op_readpc(); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa8: { + rd = op_readpc(); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x86: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x26: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x66: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x46: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x06: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa6: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x84: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x24: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x64: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x3e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0x7e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x44: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x04: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa4: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x94: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x34: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x74: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x54: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x14: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb4: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x85: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x25: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x65: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x1e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0x5e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x45: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x05: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x95: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x96: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x35: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x36: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x75: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x76: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x55: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x56: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x15: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0x16: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0xb6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x87: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x27: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x67: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x47: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x07: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x97: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x37: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x77: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x57: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x17: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x99: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_adc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x39: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_and(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x79: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_cmp(wr, rd); + (0) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x59: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_eor(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x19: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_or(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0xb9: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_sbc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x89: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x29: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x69: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x49: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x09: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0xa9: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x98: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x38: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x78: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x58: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x18: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0xb8: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x7a: { + dp = op_readpc(); + rd = op_readdp(dp); + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_addw(regs.ya, rd); + break; +} + +case 0x9a: { + dp = op_readpc(); + rd = op_readdp(dp); + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_subw(regs.ya, rd); + break; +} + +case 0x5a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); + break; +} + +case 0x4a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !!(rd & (1 << bit)); + break; +} + +case 0x6a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !(rd & (1 << bit)); + break; +} + +case 0x8a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); + break; +} + +case 0xea: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); + op_writeaddr(dp, rd); + break; +} + +case 0x0a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !!(rd & (1 << bit)); + break; +} + +case 0x2a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !(rd & (1 << bit)); + break; +} + diff --git a/snes/alt/smp/core/op_rmw.b b/snes/alt/smp/core/op_rmw.b new file mode 100755 index 00000000..425574e8 --- /dev/null +++ b/snes/alt/smp/core/op_rmw.b @@ -0,0 +1,74 @@ +inc_a(0xbc, inc, a), +inc_x(0x3d, inc, x), +inc_y(0xfc, inc, y), +dec_a(0x9c, dec, a), +dec_x(0x1d, dec, x), +dec_y(0xdc, dec, y), +asl_a(0x1c, asl, a), +lsr_a(0x5c, lsr, a), +rol_a(0x3c, rol, a), +ror_a(0x7c, ror, a) { +1:op_io(); + regs.$2 = op_$1(regs.$2); +} + +inc_dp(0xab, inc), +dec_dp(0x8b, dec), +asl_dp(0x0b, asl), +lsr_dp(0x4b, lsr), +rol_dp(0x2b, rol), +ror_dp(0x6b, ror) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd = op_$1(rd); + op_writedp(dp, rd); +} + +inc_dpx(0xbb, inc), +dec_dpx(0x9b, dec), +asl_dpx(0x1b, asl), +lsr_dpx(0x5b, lsr), +rol_dpx(0x3b, rol), +ror_dpx(0x7b, ror) { +1:dp = op_readpc(); +2:op_io(); +3:rd = op_readdp(dp + regs.x); +4:rd = op_$1(rd); + op_writedp(dp + regs.x, rd); +} + +inc_addr(0xac, inc), +dec_addr(0x8c, dec), +asl_addr(0x0c, asl), +lsr_addr(0x4c, lsr), +rol_addr(0x2c, rol), +ror_addr(0x6c, ror) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); +4:rd = op_$1(rd); + op_writeaddr(dp, rd); +} + +tset_addr_a(0x0e, |), +tclr_addr_a(0x4e, &~) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); +4:op_readaddr(dp); +5:op_writeaddr(dp, rd $1 regs.a); +} + +incw_dp(0x3a, ++), +decw_dp(0x1a, --) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); + rd$1; +3:op_writedp(dp++, rd); +4:rd += op_readdp(dp) << 8; +5:op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); +} diff --git a/snes/alt/smp/core/op_rmw.cpp b/snes/alt/smp/core/op_rmw.cpp new file mode 100755 index 00000000..f89ecacf --- /dev/null +++ b/snes/alt/smp/core/op_rmw.cpp @@ -0,0 +1,262 @@ +case 0xbc: { + op_io(); + regs.a = op_inc(regs.a); + break; +} + +case 0x3d: { + op_io(); + regs.x = op_inc(regs.x); + break; +} + +case 0xfc: { + op_io(); + regs.y = op_inc(regs.y); + break; +} + +case 0x9c: { + op_io(); + regs.a = op_dec(regs.a); + break; +} + +case 0x1d: { + op_io(); + regs.x = op_dec(regs.x); + break; +} + +case 0xdc: { + op_io(); + regs.y = op_dec(regs.y); + break; +} + +case 0x1c: { + op_io(); + regs.a = op_asl(regs.a); + break; +} + +case 0x5c: { + op_io(); + regs.a = op_lsr(regs.a); + break; +} + +case 0x3c: { + op_io(); + regs.a = op_rol(regs.a); + break; +} + +case 0x7c: { + op_io(); + regs.a = op_ror(regs.a); + break; +} + +case 0xab: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_inc(rd); + op_writedp(dp, rd); + break; +} + +case 0x8b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_dec(rd); + op_writedp(dp, rd); + break; +} + +case 0x0b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_asl(rd); + op_writedp(dp, rd); + break; +} + +case 0x4b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_lsr(rd); + op_writedp(dp, rd); + break; +} + +case 0x2b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_rol(rd); + op_writedp(dp, rd); + break; +} + +case 0x6b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_ror(rd); + op_writedp(dp, rd); + break; +} + +case 0xbb: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_inc(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x9b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_dec(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x1b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_asl(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x5b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_lsr(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x3b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_rol(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x7b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_ror(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0xac: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_inc(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x8c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_dec(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x0c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_asl(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x4c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_lsr(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x2c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_rol(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x6c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_ror(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x0e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_readaddr(dp); + op_writeaddr(dp, rd | regs.a); + break; +} + +case 0x4e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_readaddr(dp); + op_writeaddr(dp, rd &~ regs.a); + break; +} + +case 0x3a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd++; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + break; +} + +case 0x1a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd--; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + break; +} + diff --git a/snes/alt/smp/core/opcycle_misc.cpp b/snes/alt/smp/core/opcycle_misc.cpp new file mode 100755 index 00000000..963f9fc2 --- /dev/null +++ b/snes/alt/smp/core/opcycle_misc.cpp @@ -0,0 +1,696 @@ +case 0x00: { + switch(opcode_cycle++) { + case 1: + op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xef: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.pc--; + opcode_cycle = 0; + break; + } + break; +} + +case 0xff: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.pc--; + opcode_cycle = 0; + break; + } + break; +} + +case 0x9f: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbe: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x60: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.c = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x20: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.p = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x80: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.c = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0x40: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.p = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe0: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.v = 0; + regs.p.h = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0xed: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.c = !regs.p.c; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa0: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.i = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc0: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.i = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x02: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x01; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x12: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x01; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x22: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x02; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x32: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x02; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x42: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x04; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x52: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x04; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x62: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x08; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x72: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x08; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x82: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x10; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x92: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x10; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x20; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x20; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x40; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x40; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x80; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x80; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.p); + opcode_cycle = 0; + break; + } + break; +} + +case 0xae: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.a = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xce: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.x = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xee: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.y = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8e: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.p = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_io(); + break; + case 7: + op_io(); + break; + case 8: + op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9e: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_io(); + break; + case 7: + op_io(); + break; + case 8: + op_io(); + break; + case 9: + op_io(); + break; + case 10: + op_io(); + break; + case 11: + op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/snes/alt/smp/core/opcycle_mov.cpp b/snes/alt/smp/core/opcycle_mov.cpp new file mode 100755 index 00000000..635c7ca5 --- /dev/null +++ b/snes/alt/smp/core/opcycle_mov.cpp @@ -0,0 +1,806 @@ +case 0x7d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = regs.x; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = regs.y; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = regs.a; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = regs.a; + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = regs.sp; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.sp = regs.x; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe8: { + switch(opcode_cycle++) { + case 1: + regs.a = op_readpc(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcd: { + switch(opcode_cycle++) { + case 1: + regs.x = op_readpc(); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8d: { + switch(opcode_cycle++) { + case 1: + regs.y = op_readpc(); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + regs.a = op_readdp(regs.x++); + break; + case 3: + op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe4: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.a = op_readdp(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf8: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.x = op_readdp(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xeb: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.y = op_readdp(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf4: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.x = op_readdp(sp + regs.y); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfb: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe5: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.x = op_readaddr(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xec: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.y = op_readaddr(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf5: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + regs.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf6: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfa: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_readdp(regs.x); + break; + case 3: + op_writedp(regs.x, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xaf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writedp(regs.x++, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd8: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.x; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd9: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.y; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.x; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc9: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcc: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.x; + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd6: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.y; + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc7: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + sp += regs.x; + break; + case 3: + dp = op_readdp(sp); + break; + case 4: + dp |= op_readdp(sp + 1) << 8; + break; + case 5: + op_readaddr(dp); + break; + case 6: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd7: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + dp = op_readdp(sp); + break; + case 3: + dp |= op_readdp(sp + 1) << 8; + break; + case 4: + op_io(); + dp += regs.y; + break; + case 5: + op_readaddr(dp); + break; + case 6: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xba: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.a = op_readdp(sp); + break; + case 3: + op_io(); + break; + case 4: + regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xda: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + break; + case 4: + op_writedp(dp + 1, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xaa: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0xca: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); + break; + case 4: + op_io(); + break; + case 5: + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/snes/alt/smp/core/opcycle_pc.cpp b/snes/alt/smp/core/opcycle_pc.cpp new file mode 100755 index 00000000..1cdda647 --- /dev/null +++ b/snes/alt/smp/core/opcycle_pc.cpp @@ -0,0 +1,1347 @@ +case 0x2f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(0){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.z){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.z){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.c){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x90: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.c){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x70: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.v){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x50: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.v){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x30: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.n){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x10: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.n){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x03: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x01) != 0x01){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x13: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x01) == 0x01){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x23: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x02) != 0x02){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x33: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x02) == 0x02){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x43: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x04) != 0x04){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x53: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x04) == 0x04){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x63: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x08) != 0x08){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x73: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x08) == 0x08){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x83: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x10) != 0x10){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x93: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x10) == 0x10){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x20) != 0x20){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x20) == 0x20){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x40) != 0x40){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x40) == 0x40){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x80) != 0x80){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x80) == 0x80){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x2e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if(regs.a == sp){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xde: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp + regs.x); + break; + case 4: + rd = op_readpc(); + break; + case 5: + op_io(); + if(regs.a == sp){ opcode_cycle = 0; break; } + break; + case 6: + op_io(); + break; + case 7: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x6e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + wr = op_readdp(dp); + break; + case 3: + op_writedp(dp, --wr); + break; + case 4: + rd = op_readpc(); + if(wr == 0x00){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xfe: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + op_io(); + regs.y--; + break; + case 3: + op_io(); + if(regs.y == 0x00){ opcode_cycle = 0; break; } + break; + case 4: + op_io(); + break; + case 5: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x5f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + rd |= op_readpc() << 8; + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x1f: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.x; + break; + case 4: + rd = op_readaddr(dp); + break; + case 5: + rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x3f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + rd |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x4f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_writestack(regs.pc >> 8); + break; + case 5: + op_writestack(regs.pc); + regs.pc = 0xff00 | rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x01: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (0 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x11: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (1 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x21: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (2 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x31: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (3 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x41: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (4 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x51: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (5 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x61: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (6 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x71: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (7 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x81: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (8 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x91: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (9 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (10 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (11 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (12 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (13 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (14 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (15 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x0f: { + switch(opcode_cycle++) { + case 1: + rd = op_readaddr(0xffde); + break; + case 2: + rd |= op_readaddr(0xffdf) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_writestack(regs.pc >> 8); + break; + case 6: + op_writestack(regs.pc); + break; + case 7: + op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x6f: { + switch(opcode_cycle++) { + case 1: + rd = op_readstack(); + break; + case 2: + rd |= op_readstack() << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x7f: { + switch(opcode_cycle++) { + case 1: + regs.p = op_readstack(); + break; + case 2: + rd = op_readstack(); + break; + case 3: + rd |= op_readstack() << 8; + break; + case 4: + op_io(); + break; + case 5: + op_io(); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + diff --git a/snes/alt/smp/core/opcycle_read.cpp b/snes/alt/smp/core/opcycle_read.cpp new file mode 100755 index 00000000..6c19f3a9 --- /dev/null +++ b/snes/alt/smp/core/opcycle_read.cpp @@ -0,0 +1,1599 @@ +case 0x88: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x28: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x68: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xad: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x48: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x08: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x86: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x26: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x66: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x46: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x06: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x84: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x24: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x64: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x44: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x04: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x94: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x34: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x74: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x54: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x14: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x85: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x25: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x65: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x45: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x05: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x95: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x96: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x35: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x36: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x75: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x76: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x55: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x56: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x15: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x16: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb6: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x87: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x27: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x67: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x47: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x07: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x97: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x37: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x77: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x57: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x17: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x99: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_adc(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x39: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_and(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x79: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_cmp(wr, rd); + break; + case 4: + (0) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x59: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_eor(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x19: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_or(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb9: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_sbc(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x89: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x29: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x69: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x49: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x09: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x98: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x38: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x78: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x58: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x18: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + op_io(); + break; + case 4: + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_addw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + op_io(); + break; + case 4: + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_subw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0xea: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); + break; + case 4: + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c | !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c | !(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/snes/alt/smp/core/opcycle_rmw.cpp b/snes/alt/smp/core/opcycle_rmw.cpp new file mode 100755 index 00000000..eca62f02 --- /dev/null +++ b/snes/alt/smp/core/opcycle_rmw.cpp @@ -0,0 +1,550 @@ +case 0xbc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_inc(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = op_inc(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = op_inc(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_dec(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = op_dec(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = op_dec(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_asl(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_lsr(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_rol(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_ror(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xab: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_inc(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_dec(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_asl(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_lsr(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_rol(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_ror(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_inc(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_dec(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_asl(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_lsr(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_rol(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_ror(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xac: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_inc(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_dec(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_asl(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_lsr(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_rol(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_ror(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, rd | regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, rd &~ regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + rd++; + break; + case 3: + op_writedp(dp++, rd); + break; + case 4: + rd += op_readdp(dp) << 8; + break; + case 5: + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + rd--; + break; + case 3: + op_writedp(dp++, rd); + break; + case 4: + rd += op_readdp(dp) << 8; + break; + case 5: + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/snes/alt/smp/debugger/debugger.cpp b/snes/alt/smp/debugger/debugger.cpp new file mode 100755 index 00000000..9546c118 --- /dev/null +++ b/snes/alt/smp/debugger/debugger.cpp @@ -0,0 +1,75 @@ +#ifdef SMP_CPP + +void SMPDebugger::op_step() { + bool break_event = false; + + usage[regs.pc] |= UsageExec; + opcode_pc = regs.pc; + + opcode_edge = true; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); + if(step_event && step_event() == true) { + debugger.break_event = Debugger::BreakEvent::SMPStep; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + } + opcode_edge = false; + + SMP::op_step(); + synchronize_cpu(); +} + +uint8 SMPDebugger::op_read(uint16 addr) { + uint8 data = SMP::op_read(addr); + usage[addr] |= UsageRead; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void SMPDebugger::op_write(uint16 addr, uint8 data) { + SMP::op_write(addr, data); + usage[addr] |= UsageWrite; + usage[addr] &= ~UsageExec; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data); +} + +SMPDebugger::SMPDebugger() { + usage = new uint8[1 << 16](); + opcode_pc = 0xffc0; + opcode_edge = false; +} + +SMPDebugger::~SMPDebugger() { + delete[] usage; +} + +bool SMPDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //$00f0 + item("$00f0", ""); + item("Clock Speed", (unsigned)status.clock_speed); + item("Timers Enable", status.timers_enable); + item("RAM Disable", status.ram_disable); + item("RAM Writable", status.ram_writable); + item("Timers Disable", status.timers_disable); + + //$00f1 + item("$00f1", ""); + item("IPLROM Enable", status.iplrom_enable); + + //$00f2 + item("$00f2", ""); + item("DSP Address", string("0x", hex<2>(status.dsp_addr))); + + #undef item + return false; +} + +#endif diff --git a/snes/alt/smp/debugger/debugger.hpp b/snes/alt/smp/debugger/debugger.hpp new file mode 100755 index 00000000..811aa4c6 --- /dev/null +++ b/snes/alt/smp/debugger/debugger.hpp @@ -0,0 +1,27 @@ +class SMPDebugger : public SMP, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + function step_event; + + enum Usage { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + }; + uint8 *usage; + uint16 opcode_pc; + bool opcode_edge; + + void op_step(); + uint8 op_read(uint16 addr); + void op_write(uint16 addr, uint8 data); + + SMPDebugger(); + ~SMPDebugger(); + + //disassembler + void disassemble_opcode(char *output, uint16 addr); + inline uint8 disassemble_read(uint16 addr); + inline uint16 relb(int8 offset, int op_len); +}; diff --git a/snes/alt/smp/debugger/disassembler.cpp b/snes/alt/smp/debugger/disassembler.cpp new file mode 100755 index 00000000..fb76ae92 --- /dev/null +++ b/snes/alt/smp/debugger/disassembler.cpp @@ -0,0 +1,304 @@ +uint8 SMP::disassemble_read(uint16 addr) { + if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f]; + return smp.apuram[addr]; +} + +uint16 SMP::relb(int8 offset, int op_len) { + uint16 pc = regs.pc + op_len; + return pc + offset; +} + +void SMP::disassemble_opcode(char *output, uint16 addr) { + char *s, t[512]; + uint8 op, op0, op1; + uint16 opw, opdp0, opdp1; + s = output; + + sprintf(s, "..%.4x ", addr); + + op = disassemble_read(addr + 0); + op0 = disassemble_read(addr + 1); + op1 = disassemble_read(addr + 2); + opw = (op0) | (op1 << 8); + opdp0 = ((unsigned)regs.p.p << 8) + op0; + opdp1 = ((unsigned)regs.p.p << 8) + op1; + + strcpy(t, " "); + + switch(op) { + case 0x00: sprintf(t, "nop"); break; + case 0x01: sprintf(t, "tcall 0"); break; + case 0x02: sprintf(t, "set0 $%.3x", opdp0); break; + case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x04: sprintf(t, "or a,$%.3x", opdp0); break; + case 0x05: sprintf(t, "or a,$%.4x", opw); break; + case 0x06: sprintf(t, "or a,(x)"); break; + case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break; + case 0x08: sprintf(t, "or a,#$%.2x", op0); break; + case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break; + case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x0b: sprintf(t, "asl $%.3x", opdp0); break; + case 0x0c: sprintf(t, "asl $%.4x", opw); break; + case 0x0d: sprintf(t, "push p"); break; + case 0x0e: sprintf(t, "tset $%.4x,a", opw); break; + case 0x0f: sprintf(t, "brk"); break; + case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break; + case 0x11: sprintf(t, "tcall 1"); break; + case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break; + case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break; + case 0x15: sprintf(t, "or a,$%.4x+x", opw); break; + case 0x16: sprintf(t, "or a,$%.4x+y", opw); break; + case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break; + case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break; + case 0x19: sprintf(t, "or (x),(y)"); break; + case 0x1a: sprintf(t, "decw $%.3x", opdp0); break; + case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break; + case 0x1c: sprintf(t, "asl a"); break; + case 0x1d: sprintf(t, "dec x"); break; + case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break; + case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break; + case 0x20: sprintf(t, "clrp"); break; + case 0x21: sprintf(t, "tcall 2"); break; + case 0x22: sprintf(t, "set1 $%.3x", opdp0); break; + case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x24: sprintf(t, "and a,$%.3x", opdp0); break; + case 0x25: sprintf(t, "and a,$%.4x", opw); break; + case 0x26: sprintf(t, "and a,(x)"); break; + case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break; + case 0x28: sprintf(t, "and a,#$%.2x", op0); break; + case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break; + case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x2b: sprintf(t, "rol $%.3x", opdp0); break; + case 0x2c: sprintf(t, "rol $%.4x", opw); break; + case 0x2d: sprintf(t, "push a"); break; + case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break; + case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break; + case 0x31: sprintf(t, "tcall 3"); break; + case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break; + case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break; + case 0x35: sprintf(t, "and a,$%.4x+x", opw); break; + case 0x36: sprintf(t, "and a,$%.4x+y", opw); break; + case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break; + case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break; + case 0x39: sprintf(t, "and (x),(y)"); break; + case 0x3a: sprintf(t, "incw $%.3x", opdp0); break; + case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break; + case 0x3c: sprintf(t, "rol a"); break; + case 0x3d: sprintf(t, "inc x"); break; + case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break; + case 0x3f: sprintf(t, "call $%.4x", opw); break; + case 0x40: sprintf(t, "setp"); break; + case 0x41: sprintf(t, "tcall 4"); break; + case 0x42: sprintf(t, "set2 $%.3x", opdp0); break; + case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break; + case 0x45: sprintf(t, "eor a,$%.4x", opw); break; + case 0x46: sprintf(t, "eor a,(x)"); break; + case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break; + case 0x48: sprintf(t, "eor a,#$%.2x", op0); break; + case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break; + case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break; + case 0x4c: sprintf(t, "lsr $%.4x", opw); break; + case 0x4d: sprintf(t, "push x"); break; + case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break; + case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break; + case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break; + case 0x51: sprintf(t, "tcall 5"); break; + case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break; + case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break; + case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break; + case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break; + case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break; + case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break; + case 0x59: sprintf(t, "eor (x),(y)"); break; + case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break; + case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break; + case 0x5c: sprintf(t, "lsr a"); break; + case 0x5d: sprintf(t, "mov x,a"); break; + case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break; + case 0x5f: sprintf(t, "jmp $%.4x", opw); break; + case 0x60: sprintf(t, "clrc"); break; + case 0x61: sprintf(t, "tcall 6"); break; + case 0x62: sprintf(t, "set3 $%.3x", opdp0); break; + case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break; + case 0x65: sprintf(t, "cmp a,$%.4x", opw); break; + case 0x66: sprintf(t, "cmp a,(x)"); break; + case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break; + case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break; + case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break; + case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x6b: sprintf(t, "ror $%.3x", opdp0); break; + case 0x6c: sprintf(t, "ror $%.4x", opw); break; + case 0x6d: sprintf(t, "push y"); break; + case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x6f: sprintf(t, "ret"); break; + case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break; + case 0x71: sprintf(t, "tcall 7"); break; + case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break; + case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break; + case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break; + case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break; + case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break; + case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break; + case 0x79: sprintf(t, "cmp (x),(y)"); break; + case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break; + case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break; + case 0x7c: sprintf(t, "ror a"); break; + case 0x7d: sprintf(t, "mov a,x"); break; + case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break; + case 0x7f: sprintf(t, "reti"); break; + case 0x80: sprintf(t, "setc"); break; + case 0x81: sprintf(t, "tcall 8"); break; + case 0x82: sprintf(t, "set4 $%.3x", opdp0); break; + case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break; + case 0x85: sprintf(t, "adc a,$%.4x", opw); break; + case 0x86: sprintf(t, "adc a,(x)"); break; + case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break; + case 0x88: sprintf(t, "adc a,#$%.2x", op0); break; + case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break; + case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x8b: sprintf(t, "dec $%.3x", opdp0); break; + case 0x8c: sprintf(t, "dec $%.4x", opw); break; + case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break; + case 0x8e: sprintf(t, "pop p"); break; + case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break; + case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break; + case 0x91: sprintf(t, "tcall 9"); break; + case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break; + case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break; + case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break; + case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break; + case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break; + case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break; + case 0x99: sprintf(t, "adc (x),(y)"); break; + case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break; + case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break; + case 0x9c: sprintf(t, "dec a"); break; + case 0x9d: sprintf(t, "mov x,sp"); break; + case 0x9e: sprintf(t, "div ya,x"); break; + case 0x9f: sprintf(t, "xcn a"); break; + case 0xa0: sprintf(t, "ei"); break; + case 0xa1: sprintf(t, "tcall 10"); break; + case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break; + case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break; + case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break; + case 0xa6: sprintf(t, "sbc a,(x)"); break; + case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break; + case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break; + case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break; + case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xab: sprintf(t, "inc $%.3x", opdp0); break; + case 0xac: sprintf(t, "inc $%.4x", opw); break; + case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break; + case 0xae: sprintf(t, "pop a"); break; + case 0xaf: sprintf(t, "mov (x)+,a"); break; + case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break; + case 0xb1: sprintf(t, "tcall 11"); break; + case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break; + case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break; + case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break; + case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break; + case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break; + case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break; + case 0xb9: sprintf(t, "sbc (x),(y)"); break; + case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break; + case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break; + case 0xbc: sprintf(t, "inc a"); break; + case 0xbd: sprintf(t, "mov sp,x"); break; + case 0xbe: sprintf(t, "das a"); break; + case 0xbf: sprintf(t, "mov a,(x)+"); break; + case 0xc0: sprintf(t, "di"); break; + case 0xc1: sprintf(t, "tcall 12"); break; + case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break; + case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break; + case 0xc5: sprintf(t, "mov $%.4x,a", opw); break; + case 0xc6: sprintf(t, "mov (x),a"); break; + case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break; + case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break; + case 0xc9: sprintf(t, "mov $%.4x,x", opw); break; + case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break; + case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break; + case 0xcc: sprintf(t, "mov $%.4x,y", opw); break; + case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break; + case 0xce: sprintf(t, "pop x"); break; + case 0xcf: sprintf(t, "mul ya"); break; + case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break; + case 0xd1: sprintf(t, "tcall 13"); break; + case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break; + case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break; + case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break; + case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break; + case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break; + case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break; + case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break; + case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break; + case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break; + case 0xdc: sprintf(t, "dec y"); break; + case 0xdd: sprintf(t, "mov a,y"); break; + case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xdf: sprintf(t, "daa a"); break; + case 0xe0: sprintf(t, "clrv"); break; + case 0xe1: sprintf(t, "tcall 14"); break; + case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break; + case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break; + case 0xe5: sprintf(t, "mov a,$%.4x", opw); break; + case 0xe6: sprintf(t, "mov a,(x)"); break; + case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break; + case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break; + case 0xe9: sprintf(t, "mov x,$%.4x", opw); break; + case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break; + case 0xec: sprintf(t, "mov y,$%.4x", opw); break; + case 0xed: sprintf(t, "notc"); break; + case 0xee: sprintf(t, "pop y"); break; + case 0xef: sprintf(t, "sleep"); break; + case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break; + case 0xf1: sprintf(t, "tcall 15"); break; + case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break; + case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break; + case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break; + case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break; + case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break; + case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break; + case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break; + case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break; + case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break; + case 0xfc: sprintf(t, "inc y"); break; + case 0xfd: sprintf(t, "mov y,a"); break; + case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break; + case 0xff: sprintf(t, "stop"); break; + } + + t[strlen(t)] = ' '; + strcat(s, t); + + sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ", + regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya); + strcat(s, t); + + sprintf(t, "%c%c%c%c%c%c%c%c", + regs.p.n ? 'N' : 'n', + regs.p.v ? 'V' : 'v', + regs.p.p ? 'P' : 'p', + regs.p.b ? 'B' : 'b', + regs.p.h ? 'H' : 'h', + regs.p.i ? 'I' : 'i', + regs.p.z ? 'Z' : 'z', + regs.p.c ? 'C' : 'c'); + strcat(s, t); +} diff --git a/snes/alt/smp/iplrom.cpp b/snes/alt/smp/iplrom.cpp new file mode 100755 index 00000000..a2ade89d --- /dev/null +++ b/snes/alt/smp/iplrom.cpp @@ -0,0 +1,44 @@ +#ifdef SMP_CPP + +//this is the IPLROM for the S-SMP coprocessor. +//the S-SMP does not allow writing to the IPLROM. +//all writes are instead mapped to the extended +//RAM region, accessible when $f1.d7 is clear. + +const uint8 SMP::iplrom[64] = { +/*ffc0*/ 0xcd, 0xef, //mov x,#$ef +/*ffc2*/ 0xbd, //mov sp,x +/*ffc3*/ 0xe8, 0x00, //mov a,#$00 +/*ffc5*/ 0xc6, //mov (x),a +/*ffc6*/ 0x1d, //dec x +/*ffc7*/ 0xd0, 0xfc, //bne $ffc5 +/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa +/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb +/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc +/*ffd2*/ 0xd0, 0xfb, //bne $ffcf +/*ffd4*/ 0x2f, 0x19, //bra $ffef +/*ffd6*/ 0xeb, 0xf4, //mov y,$f4 +/*ffd8*/ 0xd0, 0xfc, //bne $ffd6 +/*ffda*/ 0x7e, 0xf4, //cmp y,$f4 +/*ffdc*/ 0xd0, 0x0b, //bne $ffe9 +/*ffde*/ 0xe4, 0xf5, //mov a,$f5 +/*ffe0*/ 0xcb, 0xf4, //mov $f4,y +/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a +/*ffe4*/ 0xfc, //inc y +/*ffe5*/ 0xd0, 0xf3, //bne $ffda +/*ffe7*/ 0xab, 0x01, //inc $01 +/*ffe9*/ 0x10, 0xef, //bpl $ffda +/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4 +/*ffed*/ 0x10, 0xeb, //bpl $ffda +/*ffef*/ 0xba, 0xf6, //movw ya,$f6 +/*fff1*/ 0xda, 0x00, //movw $00,ya +/*fff3*/ 0xba, 0xf4, //movw ya,$f4 +/*fff5*/ 0xc4, 0xf4, //mov $f4,a +/*fff7*/ 0xdd, //mov a,y +/*fff8*/ 0x5d, //mov x,a +/*fff9*/ 0xd0, 0xdb, //bne $ffd6 +/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x) +/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0) +}; + +#endif diff --git a/snes/alt/smp/memory.cpp b/snes/alt/smp/memory.cpp new file mode 100755 index 00000000..aecba720 --- /dev/null +++ b/snes/alt/smp/memory.cpp @@ -0,0 +1,130 @@ +unsigned SMP::port_read(unsigned addr) { + return apuram[0xf4 + (addr & 3)]; +} + +void SMP::port_write(unsigned addr, unsigned data) { + apuram[0xf4 + (addr & 3)] = data; +} + +unsigned SMP::mmio_read(unsigned addr) { + switch(addr) { + + case 0xf2: + return status.dsp_addr; + + case 0xf3: + return dsp.read(status.dsp_addr & 0x7f); + + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + synchronize_cpu(); + return cpu.port_read(addr); + + case 0xf8: + return status.ram00f8; + + case 0xf9: + return status.ram00f9; + + case 0xfd: { + unsigned result = timer0.stage3_ticks & 15; + timer0.stage3_ticks = 0; + return result; + } + + case 0xfe: { + unsigned result = timer1.stage3_ticks & 15; + timer1.stage3_ticks = 0; + return result; + } + + case 0xff: { + unsigned result = timer2.stage3_ticks & 15; + timer2.stage3_ticks = 0; + return result; + } + + } + + return 0x00; +} + +void SMP::mmio_write(unsigned addr, unsigned data) { + switch(addr) { + + case 0xf1: + status.iplrom_enable = data & 0x80; + + if(data & 0x30) { + synchronize_cpu(); + if(data & 0x20) { + cpu.port_write(3, 0x00); + cpu.port_write(2, 0x00); + } + if(data & 0x10) { + cpu.port_write(1, 0x00); + cpu.port_write(0, 0x00); + } + } + + if(timer2.enable == false && (data & 0x04)) { + timer2.stage2_ticks = 0; + timer2.stage3_ticks = 0; + } + timer2.enable = data & 0x04; + + if(timer1.enable == false && (data & 0x02)) { + timer1.stage2_ticks = 0; + timer1.stage3_ticks = 0; + } + timer1.enable = data & 0x02; + + if(timer0.enable == false && (data & 0x01)) { + timer0.stage2_ticks = 0; + timer0.stage3_ticks = 0; + } + timer0.enable = data & 0x01; + + break; + + case 0xf2: + status.dsp_addr = data; + break; + + case 0xf3: + if(status.dsp_addr & 0x80) break; + dsp.write(status.dsp_addr, data); + break; + + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + synchronize_cpu(); + port_write(addr, data); + break; + + case 0xf8: + status.ram00f8 = data; + break; + + case 0xf9: + status.ram00f9 = data; + break; + + case 0xfa: + timer0.target = data; + break; + + case 0xfb: + timer1.target = data; + break; + + case 0xfc: + timer2.target = data; + break; + + } +} diff --git a/snes/alt/smp/smp.cpp b/snes/alt/smp/smp.cpp new file mode 100755 index 00000000..0b834074 --- /dev/null +++ b/snes/alt/smp/smp.cpp @@ -0,0 +1,154 @@ +#define CYCLE_ACCURATE + +#include + +#define SMP_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + #include "debugger/disassembler.cpp" + SMPDebugger smp; +#else + SMP smp; +#endif + +#include "algorithms.cpp" +#include "core.cpp" +#include "iplrom.cpp" +#include "memory.cpp" +#include "timing.cpp" + +void SMP::synchronize_cpu() { + if(CPU::Threaded == true) { + //if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +} + +void SMP::synchronize_dsp() { + if(DSP::Threaded == true) { + //if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread); + } else { + while(dsp.clock < 0) dsp.enter(); + } +} + +void SMP::enter() { + while(clock < 0) op_step(); +} + +void SMP::power() { + Processor::frequency = system.apu_frequency(); + Processor::clock = 0; + + timer0.target = 0; + timer1.target = 0; + timer2.target = 0; + + for(unsigned n = 0; n < 256; n++) { + cycle_table_dsp[n] = (cycle_count_table[n] * 24); + cycle_table_cpu[n] = (cycle_count_table[n] * 24) * cpu.frequency; + } + + cycle_step_cpu = 24 * cpu.frequency; + + reset(); +} + +void SMP::reset() { + for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00; + + opcode_number = 0; + opcode_cycle = 0; + + regs.pc = 0xffc0; + regs.sp = 0xef; + regs.a = 0x00; + regs.x = 0x00; + regs.y = 0x00; + regs.p = 0x02; + + //$00f1 + status.iplrom_enable = true; + + //$00f2 + status.dsp_addr = 0x00; + + //$00f8,$00f9 + status.ram00f8 = 0x00; + status.ram00f9 = 0x00; + + //timers + timer0.enable = timer1.enable = timer2.enable = false; + timer0.stage1_ticks = timer1.stage1_ticks = timer2.stage1_ticks = 0; + timer0.stage2_ticks = timer1.stage2_ticks = timer2.stage2_ticks = 0; + timer0.stage3_ticks = timer1.stage3_ticks = timer2.stage3_ticks = 0; +} + +void SMP::serialize(serializer &s) { + Processor::serialize(s); + + s.array(apuram, 64 * 1024); + + s.integer(opcode_number); + s.integer(opcode_cycle); + + s.integer(regs.pc); + s.integer(regs.sp); + s.integer(regs.a); + s.integer(regs.x); + s.integer(regs.y); + + s.integer(regs.p.n); + s.integer(regs.p.v); + s.integer(regs.p.p); + s.integer(regs.p.b); + s.integer(regs.p.h); + s.integer(regs.p.i); + s.integer(regs.p.z); + s.integer(regs.p.c); + + s.integer(rd); + s.integer(wr); + s.integer(dp); + s.integer(sp); + s.integer(ya); + s.integer(bit); + + s.integer(status.iplrom_enable); + + s.integer(status.dsp_addr); + + s.integer(status.ram00f8); + s.integer(status.ram00f9); + + s.integer(timer0.enable); + s.integer(timer0.target); + s.integer(timer0.stage1_ticks); + s.integer(timer0.stage2_ticks); + s.integer(timer0.stage3_ticks); + + s.integer(timer1.enable); + s.integer(timer1.target); + s.integer(timer1.stage1_ticks); + s.integer(timer1.stage2_ticks); + s.integer(timer1.stage3_ticks); + + s.integer(timer2.enable); + s.integer(timer2.target); + + s.integer(timer2.stage1_ticks); + s.integer(timer2.stage2_ticks); + s.integer(timer2.stage3_ticks); +} + +SMP::SMP() { + apuram = new uint8[64 * 1024]; +} + +SMP::~SMP() { +} + +} diff --git a/snes/alt/smp/smp.hpp b/snes/alt/smp/smp.hpp new file mode 100755 index 00000000..44c16010 --- /dev/null +++ b/snes/alt/smp/smp.hpp @@ -0,0 +1,120 @@ +class SMP : public Processor { +public: + static const uint8 iplrom[64]; + uint8 *apuram; + + enum : bool { Threaded = false }; + alwaysinline void synchronize_cpu(); + alwaysinline void synchronize_dsp(); + + unsigned port_read(unsigned port); + void port_write(unsigned port, unsigned data); + + unsigned mmio_read(unsigned addr); + void mmio_write(unsigned addr, unsigned data); + + void enter(); + void power(); + void reset(); + + void serialize(serializer&); + SMP(); + ~SMP(); + +//private: + struct Flags { + bool n, v, p, b, h, i, z, c; + + alwaysinline operator unsigned() const { + return (n << 7) | (v << 6) | (p << 5) | (b << 4) + | (h << 3) | (i << 2) | (z << 1) | (c << 0); + }; + + alwaysinline unsigned operator=(unsigned data) { + n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10; + h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01; + return data; + } + + alwaysinline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); } + alwaysinline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); } + alwaysinline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); } + }; + + unsigned opcode_number; + unsigned opcode_cycle; + + struct Regs { + uint16 pc; + uint8 sp; + union { + uint16 ya; + struct { uint8 order_lsb2(a, y); }; + }; + uint8 x; + Flags p; + } regs; + + unsigned rd, wr, dp, sp, ya, bit; + + struct Status { + //$00f1 + bool iplrom_enable; + + //$00f2 + unsigned dsp_addr; + + //$00f8,$00f9 + unsigned ram00f8; + unsigned ram00f9; + } status; + + template + struct Timer { + bool enable; + uint8 target; + uint8 stage1_ticks; + uint8 stage2_ticks; + uint8 stage3_ticks; + + void tick(); + void tick(unsigned clocks); + }; + + Timer<128> timer0; + Timer<128> timer1; + Timer< 16> timer2; + + void tick(); + alwaysinline void op_io(); + debugvirtual alwaysinline uint8 op_read(uint16 addr); + debugvirtual alwaysinline void op_write(uint16 addr, uint8 data); + debugvirtual alwaysinline void op_step(); + static const unsigned cycle_count_table[256]; + uint64 cycle_table_cpu[256]; + unsigned cycle_table_dsp[256]; + uint64 cycle_step_cpu; + + uint8 op_adc (uint8 x, uint8 y); + uint16 op_addw(uint16 x, uint16 y); + uint8 op_and (uint8 x, uint8 y); + uint8 op_cmp (uint8 x, uint8 y); + uint16 op_cmpw(uint16 x, uint16 y); + uint8 op_eor (uint8 x, uint8 y); + uint8 op_inc (uint8 x); + uint8 op_dec (uint8 x); + uint8 op_or (uint8 x, uint8 y); + uint8 op_sbc (uint8 x, uint8 y); + uint16 op_subw(uint16 x, uint16 y); + uint8 op_asl (uint8 x); + uint8 op_lsr (uint8 x); + uint8 op_rol (uint8 x); + uint8 op_ror (uint8 x); +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern SMPDebugger smp; +#else + extern SMP smp; +#endif diff --git a/snes/alt/smp/timing.cpp b/snes/alt/smp/timing.cpp new file mode 100755 index 00000000..d278f6f4 --- /dev/null +++ b/snes/alt/smp/timing.cpp @@ -0,0 +1,26 @@ +template +void SMP::Timer::tick() { + if(++stage1_ticks < cycle_frequency) return; + + stage1_ticks = 0; + if(enable == false) return; + + if(++stage2_ticks != target) return; + + stage2_ticks = 0; + stage3_ticks = (stage3_ticks + 1) & 15; +} + +template +void SMP::Timer::tick(unsigned clocks) { + stage1_ticks += clocks; + if(stage1_ticks < cycle_frequency) return; + + stage1_ticks -= cycle_frequency; + if(enable == false) return; + + if(++stage2_ticks != target) return; + + stage2_ticks = 0; + stage3_ticks = (stage3_ticks + 1) & 15; +} diff --git a/snes/audio/audio.cpp b/snes/audio/audio.cpp new file mode 100755 index 00000000..ad469899 --- /dev/null +++ b/snes/audio/audio.cpp @@ -0,0 +1,69 @@ +#ifdef SYSTEM_CPP + +Audio audio; + +void Audio::coprocessor_enable(bool state) { + coprocessor = state; + dspaudio.clear(); + + dsp_rdoffset = cop_rdoffset = 0; + dsp_wroffset = cop_wroffset = 0; + dsp_length = cop_length = 0; +} + +void Audio::coprocessor_frequency(double input_frequency) { + dspaudio.setFrequency(input_frequency); + dspaudio.setResampler(nall::DSP::ResampleEngine::Sinc); + dspaudio.setResamplerFrequency(system.apu_frequency() / 768.0); +} + +void Audio::sample(int16 lsample, int16 rsample) { + if(coprocessor == false) return interface->audioSample(lsample, rsample); + + dsp_buffer[dsp_wroffset] = ((uint16)lsample << 0) + ((uint16)rsample << 16); + dsp_wroffset = (dsp_wroffset + 1) & buffer_mask; + dsp_length = (dsp_length + 1) & buffer_mask; + flush(); +} + +void Audio::coprocessor_sample(int16 lsample, int16 rsample) { + signed samples[] = { lsample, rsample }; + dspaudio.sample(samples); + while(dspaudio.pending()) { + dspaudio.read(samples); + + cop_buffer[cop_wroffset] = ((uint16)samples[0] << 0) + ((uint16)samples[1] << 16); + cop_wroffset = (cop_wroffset + 1) & buffer_mask; + cop_length = (cop_length + 1) & buffer_mask; + flush(); + } +} + +void Audio::init() { +} + +void Audio::flush() { + while(dsp_length > 0 && cop_length > 0) { + uint32 dsp_sample = dsp_buffer[dsp_rdoffset]; + uint32 cop_sample = cop_buffer[cop_rdoffset]; + + dsp_rdoffset = (dsp_rdoffset + 1) & buffer_mask; + cop_rdoffset = (cop_rdoffset + 1) & buffer_mask; + + dsp_length--; + cop_length--; + + signed dsp_left = (int16)(dsp_sample >> 0); + signed dsp_right = (int16)(dsp_sample >> 16); + + signed cop_left = (int16)(cop_sample >> 0); + signed cop_right = (int16)(cop_sample >> 16); + + interface->audioSample( + sclamp<16>((dsp_left + cop_left ) / 2), + sclamp<16>((dsp_right + cop_right) / 2) + ); + } +} + +#endif diff --git a/snes/audio/audio.hpp b/snes/audio/audio.hpp new file mode 100755 index 00000000..1b4dc365 --- /dev/null +++ b/snes/audio/audio.hpp @@ -0,0 +1,20 @@ +struct Audio { + void coprocessor_enable(bool state); + void coprocessor_frequency(double frequency); + void sample(int16 lsample, int16 rsample); + void coprocessor_sample(int16 lsample, int16 rsample); + void init(); + +private: + nall::DSP dspaudio; + bool coprocessor; + enum : unsigned { buffer_size = 256, buffer_mask = buffer_size - 1 }; + uint32 dsp_buffer[buffer_size], cop_buffer[buffer_size]; + unsigned dsp_rdoffset, cop_rdoffset; + unsigned dsp_wroffset, cop_wroffset; + unsigned dsp_length, cop_length; + + void flush(); +}; + +extern Audio audio; diff --git a/snes/cartridge/cartridge.cpp b/snes/cartridge/cartridge.cpp new file mode 100755 index 00000000..f8c05fa3 --- /dev/null +++ b/snes/cartridge/cartridge.cpp @@ -0,0 +1,88 @@ +#include + +#include +#include + +#define CARTRIDGE_CPP +namespace SNES { + +#include "markup.cpp" +#include "serialization.cpp" + +Cartridge cartridge; + +void Cartridge::load(Mode cartridge_mode, const char *markup) { + mode = cartridge_mode; + region = Region::NTSC; + ram_size = 0; + + has_bsx_slot = false; + has_nss_dip = false; + has_superfx = false; + has_sa1 = false; + has_necdsp = false; + has_hitachidsp = false; + has_srtc = false; + has_sdd1 = false; + has_spc7110 = false; + has_spc7110rtc = false; + has_obc1 = false; + has_st0018 = false; + has_msu1 = false; + has_link = false; + + nvram.reset(); + + parse_markup(markup); +//print(markup, "\n\n"); + + if(ram_size > 0) { + ram.map(allocate(ram_size, 0xff), ram_size); + nvram.append({ ".srm", ram.data(), ram.size() }); + } + + rom.write_protect(true); + ram.write_protect(false); + + crc32 = crc32_calculate(rom.data(), rom.size()); + + switch((Mode)mode) { + case Mode::Normal: + case Mode::BsxSlotted: + sha256 = nall::sha256(rom.data(), rom.size()); + break; + case Mode::Bsx: + sha256 = nall::sha256(bsxflash.memory.data(), bsxflash.memory.size()); + break; + case Mode::SufamiTurbo: + sha256 = nall::sha256(sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size()); + break; + case Mode::SuperGameBoy: + sha256 = GameBoy::cartridge.sha256(); + break; + } + + system.load(); + loaded = true; +} + +void Cartridge::unload() { + if(loaded == false) return; + + system.unload(); + rom.reset(); + ram.reset(); + + loaded = false; +} + +Cartridge::Cartridge() { + loaded = false; + unload(); +} + +Cartridge::~Cartridge() { + unload(); +} + +} diff --git a/snes/cartridge/cartridge.hpp b/snes/cartridge/cartridge.hpp new file mode 100755 index 00000000..f384fac9 --- /dev/null +++ b/snes/cartridge/cartridge.hpp @@ -0,0 +1,116 @@ +struct Cartridge : property { + enum class Mode : unsigned { + Normal, + BsxSlotted, + Bsx, + SufamiTurbo, + SuperGameBoy, + }; + + enum class Region : unsigned { + NTSC, + PAL, + }; + + enum class Slot : unsigned { + Base, + Bsx, + SufamiTurbo, + SufamiTurboA, + SufamiTurboB, + GameBoy, + }; + + MappedRAM rom; + MappedRAM ram; + + readonly loaded; + readonly crc32; + readonly sha256; + + readonly mode; + readonly region; + readonly ram_size; + + readonly has_bsx_slot; + readonly has_nss_dip; + readonly has_superfx; + readonly has_sa1; + readonly has_necdsp; + readonly has_hitachidsp; + readonly has_srtc; + readonly has_sdd1; + readonly has_spc7110; + readonly has_spc7110rtc; + readonly has_obc1; + readonly has_st0018; + readonly has_msu1; + readonly has_link; + + struct NonVolatileRAM { + const string id; + uint8_t *data; + unsigned size; + Slot slot; + NonVolatileRAM() : id(""), data(0), size(0), slot(Slot::Base) {} + NonVolatileRAM(const string id, uint8_t *data, unsigned size, Slot slot = Slot::Base) + : id(id), data(data), size(size), slot(slot) {} + }; + linear_vector nvram; + + struct Mapping { + function read; + function write; + Bus::MapMode mode; + unsigned banklo; + unsigned bankhi; + unsigned addrlo; + unsigned addrhi; + unsigned offset; + unsigned size; + + Mapping(); + Mapping(const function&, const function&); + Mapping(Memory&); + }; + linear_vector mapping; + + struct Information { + struct NSS { + lstring setting; + lstring option[16]; + } nss; + } information; + + void load(Mode, const char*); + void unload(); + + void serialize(serializer&); + Cartridge(); + ~Cartridge(); + +private: + void parse_markup(const char*); + unsigned parse_markup_integer(cstring&); + void parse_markup_map(Mapping&, BML::Node&); + + void parse_markup_rom(BML::Node&); + void parse_markup_ram(BML::Node&); + void parse_markup_nss(BML::Node&); + void parse_markup_icd2(BML::Node&); + void parse_markup_superfx(BML::Node&); + void parse_markup_sa1(BML::Node&); + void parse_markup_necdsp(BML::Node&); + void parse_markup_hitachidsp(BML::Node&); + void parse_markup_bsx(BML::Node&); + void parse_markup_sufamiturbo(BML::Node&); + void parse_markup_srtc(BML::Node&); + void parse_markup_sdd1(BML::Node&); + void parse_markup_spc7110(BML::Node&); + void parse_markup_obc1(BML::Node&); + void parse_markup_setarisc(BML::Node&); + void parse_markup_msu1(BML::Node&); + void parse_markup_link(BML::Node&); +}; + +extern Cartridge cartridge; diff --git a/snes/cartridge/markup.cpp b/snes/cartridge/markup.cpp new file mode 100755 index 00000000..2696a17b --- /dev/null +++ b/snes/cartridge/markup.cpp @@ -0,0 +1,557 @@ +#ifdef CARTRIDGE_CPP + +void Cartridge::parse_markup(const char *markup) { + mapping.reset(); + information.nss.setting.reset(); + + BML::Document document(markup); + auto &cartridge = document["cartridge"]; + region = cartridge["region"].value != "PAL" ? Region::NTSC : Region::PAL; + + parse_markup_rom(cartridge["rom"]); + parse_markup_ram(cartridge["ram"]); + parse_markup_nss(cartridge["nss"]); + parse_markup_icd2(cartridge["icd2"]); + parse_markup_sa1(cartridge["sa1"]); + parse_markup_superfx(cartridge["superfx"]); + parse_markup_necdsp(cartridge["necdsp"]); + parse_markup_hitachidsp(cartridge["hitachidsp"]); + parse_markup_bsx(cartridge["bsx"]); + parse_markup_sufamiturbo(cartridge["sufamiturbo"]); + parse_markup_srtc(cartridge["srtc"]); + parse_markup_sdd1(cartridge["sdd1"]); + parse_markup_spc7110(cartridge["spc7110"]); + parse_markup_obc1(cartridge["obc1"]); + parse_markup_setarisc(cartridge["setarisc"]); + parse_markup_msu1(cartridge["msu1"]); + parse_markup_link(cartridge["link"]); +} + +// + +unsigned Cartridge::parse_markup_integer(cstring &data) { + if(strbegin(data, "0x")) return hex(data); + return decimal(data); +} + +void Cartridge::parse_markup_map(Mapping &m, BML::Node &map) { + m.offset = parse_markup_integer(map["offset"].value); + m.size = parse_markup_integer(map["size"].value); + + string data = map["mode"].value; + if(data == "direct") m.mode = Bus::MapMode::Direct; + if(data == "linear") m.mode = Bus::MapMode::Linear; + if(data == "shadow") m.mode = Bus::MapMode::Shadow; + + lstring part; + part.split(":", map["address"].value); + if(part.size() != 2) return; + + lstring subpart; + subpart.split("-", part[0]); + if(subpart.size() == 1) { + m.banklo = hex(subpart[0]); + m.bankhi = m.banklo; + } else if(subpart.size() == 2) { + m.banklo = hex(subpart[0]); + m.bankhi = hex(subpart[1]); + } + + subpart.split("-", part[1]); + if(subpart.size() == 1) { + m.addrlo = hex(subpart[0]); + m.addrhi = m.addrlo; + } else if(subpart.size() == 2) { + m.addrlo = hex(subpart[0]); + m.addrhi = hex(subpart[1]); + } +} + +// + +void Cartridge::parse_markup_rom(BML::Node &root) { + if(root.exists() == false) return; + for(auto &node : root) { + if(node.name != "map") continue; + Mapping m(rom); + parse_markup_map(m, node); + if(m.size == 0) m.size = rom.size(); + mapping.append(m); + } +} + +void Cartridge::parse_markup_ram(BML::Node &root) { + if(root.exists() == false) return; + ram_size = parse_markup_integer(root["size"].value); + for(auto &node : root) { + Mapping m(ram); + parse_markup_map(m, node); + if(m.size == 0) m.size = ram_size; + mapping.append(m); + } +} + +void Cartridge::parse_markup_nss(BML::Node &root) { + if(root.exists() == false) return; + has_nss_dip = true; + for(auto &node : root) { + if(node.name != "setting") continue; + unsigned number = information.nss.setting.size(); + if(number >= 16) break; //more than 16 DIP switches is not physically possible + + information.nss.option[number].reset(); + information.nss.setting[number] = node["name"].value; + for(auto &leaf : node) { + if(leaf.name != "option") continue; + string name = leaf["name"].value; + unsigned value = parse_markup_integer(leaf["value"].value); + information.nss.option[number].append({ hex<4>(value), ":", name }); + } + } +} + +void Cartridge::parse_markup_icd2(BML::Node &root) { + if(root.exists() == false) return; + if(mode != Mode::SuperGameBoy) return; + + icd2.revision = max(1, parse_markup_integer(root["revision"].value)); + + for(auto &node : root) { + if(node.name != "map") continue; + Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_superfx(BML::Node &root) { + if(root.exists() == false) return; + has_superfx = true; + + for(auto &node : root) { + if(node.name == "rom") { + for(auto &leaf : node) { + if(leaf.name != "map") continue; + Mapping m(superfx.rom); + parse_markup_map(m, leaf); + mapping.append(m); + } + } + if(node.name == "ram") { + for(auto &leaf : node) { + if(leaf.name == "size") { + ram_size = parse_markup_integer(leaf.value); + continue; + } + if(leaf.name != "map") continue; + Mapping m(superfx.ram); + parse_markup_map(m, leaf); + if(m.size == 0) m.size = ram_size; + mapping.append(m); + } + } + if(node.name == "mmio") { + for(auto &leaf : node) { + if(leaf.name != "map") continue; + Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx }); + parse_markup_map(m, leaf); + mapping.append(m); + } + } + } +} + +void Cartridge::parse_markup_sa1(BML::Node &root) { + if(root.exists() == false) return; + has_sa1 = true; + + auto &mcurom = root["mcu"]["rom"]; + auto &mcuram = root["mcu"]["ram"]; + auto &iram = root["iram"]; + auto &bwram = root["bwram"]; + auto &mmio = root["mmio"]; + + for(auto &node : mcurom) { + if(node.name != "map") continue; + Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 }); + parse_markup_map(m, node); + mapping.append(m); + } + + for(auto &node : mcuram) { + if(node.name != "map") continue; + Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 }); + parse_markup_map(m, node); + mapping.append(m); + } + + for(auto &node : iram) { + if(node.name != "map") continue; + Mapping m(sa1.cpuiram); + parse_markup_map(m, node); + if(m.size == 0) m.size = 2048; + mapping.append(m); + } + + ram_size = parse_markup_integer(bwram["size"].value); + for(auto &node : bwram) { + if(node.name != "map") continue; + Mapping m(sa1.cpubwram); + parse_markup_map(m, node); + if(m.size == 0) m.size = ram_size; + mapping.append(m); + } + + for(auto &node : mmio) { + if(node.name != "map") continue; + Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_necdsp(BML::Node &root) { + if(root.exists() == false) return; + has_necdsp = true; + + for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000; + for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000; + + necdsp.frequency = parse_markup_integer(root["frequency"].value); + if(necdsp.frequency == 0) necdsp.frequency = 8000000; + necdsp.revision + = root["model"].value == "uPD7725" ? NECDSP::Revision::uPD7725 + : root["model"].value == "uPD96050" ? NECDSP::Revision::uPD96050 + : NECDSP::Revision::uPD7725; + string firmware = root["firmware"].value; + string sha256 = root["sha256"].value; + + string path = { dir(interface->path(Slot::Base, ".dsp")), firmware }; + unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384); + unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048); + unsigned filesize = promsize * 3 + dromsize * 2; + + file fp; + if(fp.open(path, file::mode::read) == false) { + interface->message({ "Warning: NEC DSP firmware ", firmware, " is missing." }); + } else if(fp.size() != filesize) { + interface->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." }); + fp.close(); + } else { + for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3); + for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2); + + if(sha256 != "") { + //XML file specified SHA256 sum for program. Verify file matches the hash. + fp.seek(0); + uint8_t data[filesize]; + fp.read(data, filesize); + + if(sha256 != nall::sha256(data, filesize)) { + interface->message({ "Warning: NEC DSP firmware ", firmware, " SHA256 sum is incorrect." }); + } + } + + fp.close(); + } + + for(auto &node : root) { + if(node.name == "dr") { + for(auto &leaf : node) { + Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp }); + parse_markup_map(m, leaf); + mapping.append(m); + } + } + if(node.name == "sr") { + for(auto &leaf : node) { + Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp }); + parse_markup_map(m, leaf); + mapping.append(m); + } + } + if(node.name == "dp") { + for(auto &leaf : node) { + Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp }); + parse_markup_map(m, leaf); + mapping.append(m); + } + } + } +} + +void Cartridge::parse_markup_hitachidsp(BML::Node &root) { + if(root.exists() == false) return; + has_hitachidsp = true; + + for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000; + + hitachidsp.frequency = parse_markup_integer(root["frequency"].value); + if(hitachidsp.frequency == 0) hitachidsp.frequency = 20000000; + string firmware = root["firmware"].value; + string sha256 = root["sha256"].value; + + string path = { dir(interface->path(Slot::Base, ".dsp")), firmware }; + file fp; + if(fp.open(path, file::mode::read) == false) { + interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." }); + } else if(fp.size() != 1024 * 3) { + interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." }); + fp.close(); + } else { + for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3); + + if(sha256 != "") { + //XML file specified SHA256 sum for program. Verify file matches the hash. + fp.seek(0); + uint8 data[3072]; + fp.read(data, 3072); + + if(sha256 != nall::sha256(data, 3072)) { + interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." }); + } + } + + fp.close(); + } + + for(auto &node : root) { + if(node.name == "rom") { + for(auto &leaf : node) { + if(leaf.name != "map") continue; + Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp }); + parse_markup_map(m, leaf); + mapping.append(m); + } + } + if(node.name == "mmio") { + for(auto &leaf : node) { + Mapping m({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp }); + parse_markup_map(m, leaf); + mapping.append(m); + } + } + } +} + +void Cartridge::parse_markup_bsx(BML::Node &root) { + if(root.exists() == false) return; + if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return; + + for(auto &node : root["slot"]) { + if(node.name != "map") continue; + Mapping m(bsxflash.memory); + parse_markup_map(m, node); + mapping.append(m); + } + + for(auto &node : root["mmio"]) { + if(node.name != "map") continue; + Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge }); + parse_markup_map(m, node); + mapping.append(m); + } + + for(auto &node : root["mcu"]) { + if(node.name != "map") continue; + Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_sufamiturbo(BML::Node &root) { + if(root.exists() == false) return; + if(mode != Mode::SufamiTurbo) return; + + for(auto &slot : root) { + if(slot.name != "slot") continue; + bool slotid = slot["id"].value == "A" ? 0 : slot["id"].value == "B" ? 1 : 0; + for(auto &node : slot) { + if(node.name == "rom") { + for(auto &leaf : node) { + if(leaf.name != "map") continue; + Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom; + Mapping m(memory); + parse_markup_map(m, leaf); + if(m.size == 0) m.size = memory.size(); + if(m.size) mapping.append(m); + } + } + if(node.name == "ram") { + unsigned ram_size = parse_markup_integer(node["size"].value); + for(auto &leaf : node) { + if(leaf.name != "map") continue; + Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram; + Mapping m(memory); + parse_markup_map(m, leaf); + if(m.size == 0) m.size = ram_size; + if(m.size) mapping.append(m); + } + } + } + } +} + +void Cartridge::parse_markup_srtc(BML::Node &root) { + if(root.exists() == false) return; + has_srtc = true; + + for(auto &node : root) { + if(node.name != "map") continue; + Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_sdd1(BML::Node &root) { + if(root.exists() == false) return; + has_sdd1 = true; + + for(auto &node : root["mmio"]) { + if(node.name != "map") continue; + Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 }); + parse_markup_map(m, node); + mapping.append(m); + } + + for(auto &node : root["mcu"]) { + if(node.name != "map") continue; + Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_spc7110(BML::Node &root) { + if(root.exists() == false) return; + has_spc7110 = true; + + auto &ram = root["ram"]; + auto &mmio = root["mmio"]; + auto &mcu = root["mcu"]; + auto &dcu = root["dcu"]; + auto &rtc = root["rtc"]; + + ram_size = parse_markup_integer(ram["size"].value); + for(auto &node : ram) { + if(node.name != "map") continue; + Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 }); + parse_markup_map(m, node); + mapping.append(m); + } + + for(auto &node : mmio) { + if(node.name != "map") continue; + Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 }); + parse_markup_map(m, node); + mapping.append(m); + } + + spc7110.data_rom_offset = parse_markup_integer(mcu["offset"].value); + if(spc7110.data_rom_offset == 0) spc7110.data_rom_offset = 0x100000; + for(auto &node : mcu) { + if(node.name != "map") continue; + Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 }); + parse_markup_map(m, node); + mapping.append(m); + } + + for(auto &node : dcu) { + if(node.name != "map") continue; + Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 }); + parse_markup_map(m, node); + mapping.append(m); + } + + for(auto &node : rtc) { + if(node.name != "map") continue; + Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_obc1(BML::Node &root) { + if(root.exists() == false) return; + has_obc1 = true; + + for(auto &node : root) { + if(node.name != "map") continue; + Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_setarisc(BML::Node &root) { + if(root.exists() == false) return; + has_st0018 = true; + + for(auto &node : root) { + if(node.name != "map") continue; + Mapping m({ &ST0018::mmio_read, &st0018 }, { &ST0018::mmio_write, &st0018 }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_msu1(BML::Node &root) { + if(root.exists() == false) { + has_msu1 = file::exists(interface->path(Cartridge::Slot::Base, ".msu")); + if(has_msu1) { + Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 }); + m.banklo = 0x00, m.bankhi = 0x3f, m.addrlo = 0x2000, m.addrhi = 0x2007; + mapping.append(m); + m.banklo = 0x80, m.bankhi = 0xbf, m.addrlo = 0x2000, m.addrhi = 0x2007; + mapping.append(m); + } + return; + } + + has_msu1 = true; + + for(auto &node : root) { + if(node.name != "map") continue; + Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +void Cartridge::parse_markup_link(BML::Node &root) { + if(root.exists() == false) return; + has_link = true; + + link.frequency = max(1, parse_markup_integer(root["frequency"].value)); + link.program = root["program"].value; + + for(auto &node : root) { + if(node.name != "map") continue; + Mapping m({ &Link::read, &link }, { &Link::write, &link }); + parse_markup_map(m, node); + mapping.append(m); + } +} + +Cartridge::Mapping::Mapping() { + mode = Bus::MapMode::Direct; + banklo = bankhi = addrlo = addrhi = offset = size = 0; +} + +Cartridge::Mapping::Mapping(Memory &memory) { + read = { &Memory::read, &memory }; + write = { &Memory::write, &memory }; + mode = Bus::MapMode::Direct; + banklo = bankhi = addrlo = addrhi = offset = size = 0; +} + +Cartridge::Mapping::Mapping(const function &read_, const function &write_) { + read = read_; + write = write_; + mode = Bus::MapMode::Direct; + banklo = bankhi = addrlo = addrhi = offset = size = 0; +} + +#endif diff --git a/snes/cartridge/serialization.cpp b/snes/cartridge/serialization.cpp new file mode 100755 index 00000000..f7e0abfa --- /dev/null +++ b/snes/cartridge/serialization.cpp @@ -0,0 +1,9 @@ +#ifdef CARTRIDGE_CPP + +void Cartridge::serialize(serializer &s) { + for(auto &ram : nvram) { + if(ram.size) s.array(ram.data, ram.size); + } +} + +#endif diff --git a/snes/cheat/cheat.cpp b/snes/cheat/cheat.cpp new file mode 100755 index 00000000..46c42d1c --- /dev/null +++ b/snes/cheat/cheat.cpp @@ -0,0 +1,110 @@ +#include + +#define CHEAT_CPP +namespace SNES { + +Cheat cheat; + +bool Cheat::enabled() const { + return system_enabled; +} + +void Cheat::enable(bool state) { + system_enabled = state; + cheat_enabled = system_enabled && code_enabled; +} + +void Cheat::synchronize() { + memset(override, 0x00, 16 * 1024 * 1024); + code_enabled = size() > 0; + + for(unsigned i = 0; i < size(); i++) { + const CheatCode &code = operator[](i); + + unsigned addr = mirror(code.addr); + 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); + override[mirroraddr] = true; + + mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff); + override[mirroraddr] = true; + } + } + } + + cheat_enabled = system_enabled && code_enabled; +} + +uint8 Cheat::read(unsigned addr) const { + addr = mirror(addr); + + for(unsigned i = 0; i < size(); i++) { + const CheatCode &code = operator[](i); + if(addr == mirror(code.addr)) { + return code.data; + } + } + + return 0x00; +} + +void Cheat::init() { + memset(override, 0x00, 16 * 1024 * 1024); +} + +Cheat::Cheat() { + override = new uint8[16 * 1024 * 1024]; + system_enabled = true; +} + +Cheat::~Cheat() { + delete[] override; +} + +bool Cheat::decode(const string &code, unsigned &addr, unsigned &data) { + string t = code; + t.lower(); + + #define ischr(n) ((n >= '0' && n <= '9') || (n >= 'a' && n <= 'f')) + + if(t.wildcard("??????:??")) { + //Direct + t = { substr(t, 0, 6), substr(t, 7, 2) }; + for(unsigned n = 0; n < 8; n++) if(!ischr(t[n])) return false; //validate input + unsigned r = hex(t); + + addr = r >> 8; + data = r & 0xff; + return true; + } + + if(t.wildcard("????" "-" "????")) { + //Game Genie + t = { substr(t, 0, 4), substr(t, 5, 4) }; + for(unsigned n = 0; n < 8; n++) if(!ischr(t[n])) return false; //validate input + t.transform("df4709156bc8a23e", "0123456789abcdef"); + unsigned r = hex(t); + static unsigned bits[] = { 13, 12, 11, 10, 5, 4, 3, 2, 23, 22, 21, 20, 1, 0, 15, 14, 19, 18, 17, 16, 9, 8, 7, 6 }; + + addr = 0; + for(unsigned n = 0; n < 24; n++) addr |= r & (1 << bits[n]) ? 0x800000 >> n : 0; + data = r >> 24; + return true; + } else { + return false; + } + + #undef ischr +} + +unsigned Cheat::mirror(unsigned addr) const { + //$00-3f|80-bf:0000-1fff -> $7e:0000-1fff + if((addr & 0x40e000) == 0x000000) return (0x7e0000 + (addr & 0x1fff)); + return addr; +} + +} diff --git a/snes/cheat/cheat.hpp b/snes/cheat/cheat.hpp new file mode 100755 index 00000000..306b99b1 --- /dev/null +++ b/snes/cheat/cheat.hpp @@ -0,0 +1,27 @@ +struct CheatCode { + unsigned addr; + unsigned data; +}; + +struct Cheat : public linear_vector { + uint8 *override; + + bool enabled() const; + void enable(bool); + void synchronize(); + uint8 read(unsigned) const; + void init(); + + Cheat(); + ~Cheat(); + + static bool decode(const string&, unsigned&, unsigned&); + +private: + bool system_enabled; + bool code_enabled; + bool cheat_enabled; + unsigned mirror(unsigned) const; +}; + +extern Cheat cheat; diff --git a/snes/chip/bsx/bsx.cpp b/snes/chip/bsx/bsx.cpp new file mode 100755 index 00000000..450c0423 --- /dev/null +++ b/snes/chip/bsx/bsx.cpp @@ -0,0 +1,8 @@ +#include + +#define BSX_CPP +namespace SNES { + #include "satellaview/satellaview.cpp" + #include "cartridge/cartridge.cpp" + #include "flash/flash.cpp" +} diff --git a/snes/chip/bsx/bsx.hpp b/snes/chip/bsx/bsx.hpp new file mode 100755 index 00000000..5f3895bd --- /dev/null +++ b/snes/chip/bsx/bsx.hpp @@ -0,0 +1,3 @@ +#include "satellaview/satellaview.hpp" +#include "cartridge/cartridge.hpp" +#include "flash/flash.hpp" diff --git a/snes/chip/bsx/cartridge/cartridge.cpp b/snes/chip/bsx/cartridge/cartridge.cpp new file mode 100755 index 00000000..ade0f11d --- /dev/null +++ b/snes/chip/bsx/cartridge/cartridge.cpp @@ -0,0 +1,149 @@ +#ifdef BSX_CPP + +BSXCartridge bsxcartridge; + +void BSXCartridge::init() { +} + +void BSXCartridge::load() { + sram.map(allocate(32 * 1024, 0xff), 32 * 1024); + sram.write_protect(false); + cartridge.nvram.append({ ".bss", sram.data(), sram.size() }); + + psram.map(allocate(512 * 1024, 0xff), 512 * 1024); + psram.write_protect(false); + cartridge.nvram.append({ ".bsp", psram.data(), psram.size() }); +} + +void BSXCartridge::unload() { +} + +void BSXCartridge::power() { + reset(); +} + +void BSXCartridge::reset() { + for(unsigned i = 0; i < 16; i++) r[i] = 0x00; + r[0x07] = 0x80; + r[0x08] = 0x80; + mmio_commit(); +} + +uint8 BSXCartridge::memory_access(bool write, Memory &memory, unsigned addr, uint8 data) { + if(write == 0) return memory_read(memory, addr); + memory_write(memory, addr, data); +} + +uint8 BSXCartridge::memory_read(Memory &memory, unsigned addr) { + addr = bus.mirror(addr, memory.size()); + return memory.read(addr); +} + +void BSXCartridge::memory_write(Memory &memory, unsigned addr, uint8 data) { + addr = bus.mirror(addr, memory.size()); + return memory.write(addr, data); +} + +//mcu_access() allows mcu_read() and mcu_write() to share decoding logic +uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) { + if(within<0x00, 0x1f, 0x8000, 0xffff>(addr)) { + if(r07 == 1) { + addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff); + return memory_access(write, cartridge.rom, addr, data); + } + } + + if(within<0x80, 0x9f, 0x8000, 0xffff>(addr)) { + if(r08 == 1) { + addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff); + return memory_access(write, cartridge.rom, addr, data); + } + } + + if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) { + return memory_access(write, psram, addr, data); + } + + if(within<0x40, 0x4f, 0x0000, 0xffff>(addr)) { + if(r05 == 0) return memory_access(write, psram, addr & 0x0fffff, data); + } + + if(within<0x50, 0x5f, 0x0000, 0xffff>(addr)) { + if(r06 == 0) return memory_access(write, psram, addr & 0x0fffff, data); + } + + if(within<0x60, 0x6f, 0x0000, 0xffff>(addr)) { + if(r03 == 1) return memory_access(write, psram, addr & 0x0fffff, data); + } + + if(within<0x70, 0x77, 0x0000, 0xffff>(addr)) { + return memory_access(write, psram, addr & 0x07ffff, data); + } + + if(within<0x00, 0x3f, 0x8000, 0xffff>(addr) + || within<0x40, 0x7f, 0x0000, 0xffff>(addr) + || within<0x80, 0xbf, 0x8000, 0xffff>(addr) + || within<0xc0, 0xff, 0x0000, 0xffff>(addr) + ) { + if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff); + Memory &memory = (r01 == 0 ? (Memory&)bsxflash : (Memory&)psram); + return memory_access(write, memory, addr & 0x7fffff, data); + } + + return cpu.regs.mdr; +} + +uint8 BSXCartridge::mcu_read(unsigned addr) { + return mcu_access(0, addr); +} + +void BSXCartridge::mcu_write(unsigned addr, uint8 data) { + mcu_access(1, addr, data); +} + +uint8 BSXCartridge::mmio_read(unsigned addr) { + if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) { + uint8 n = (addr >> 16) & 15; + return r[n]; + } + + if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) { + return memory_read(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff)); + } + + return 0x00; +} + +void BSXCartridge::mmio_write(unsigned addr, uint8 data) { + if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) { + uint8 n = (addr >> 16) & 15; + r[n] = data; + if(n == 0x0e && data & 0x80) mmio_commit(); + return; + } + + if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) { + return memory_write(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data); + } +} + +void BSXCartridge::mmio_commit() { + r00 = r[0x00] & 0x80; + r01 = r[0x01] & 0x80; + r02 = r[0x02] & 0x80; + r03 = r[0x03] & 0x80; + r04 = r[0x04] & 0x80; + r05 = r[0x05] & 0x80; + r06 = r[0x06] & 0x80; + r07 = r[0x07] & 0x80; + r08 = r[0x08] & 0x80; + r09 = r[0x09] & 0x80; + r0a = r[0x0a] & 0x80; + r0b = r[0x0b] & 0x80; + r0c = r[0x0c] & 0x80; + r0d = r[0x0d] & 0x80; + r0e = r[0x0e] & 0x80; + r0f = r[0x0f] & 0x80; +} + +#endif diff --git a/snes/chip/bsx/cartridge/cartridge.hpp b/snes/chip/bsx/cartridge/cartridge.hpp new file mode 100755 index 00000000..eb5f9bf9 --- /dev/null +++ b/snes/chip/bsx/cartridge/cartridge.hpp @@ -0,0 +1,32 @@ +class BSXCartridge { +public: + MappedRAM sram; + MappedRAM psram; + + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 memory_access(bool write, Memory &memory, unsigned addr, uint8 data); + uint8 memory_read(Memory &memory, unsigned addr); + void memory_write(Memory &memory, unsigned addr, uint8 data); + + uint8 mcu_access(bool write, unsigned addr, uint8 data = 0x00); + uint8 mcu_read(unsigned addr); + void mcu_write(unsigned addr, uint8 data); + + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + void mmio_commit(); + +private: + uint8 r[16]; + bool r00, r01, r02, r03; + bool r04, r05, r06, r07; + bool r08, r09, r0a, r0b; + bool r0c, r0d, r0e, r0f; +}; + +extern BSXCartridge bsxcartridge; diff --git a/snes/chip/bsx/flash/flash.cpp b/snes/chip/bsx/flash/flash.cpp new file mode 100755 index 00000000..316f55c2 --- /dev/null +++ b/snes/chip/bsx/flash/flash.cpp @@ -0,0 +1,128 @@ +#ifdef BSX_CPP + +BSXFlash bsxflash; + +void BSXFlash::init() { +} + +void BSXFlash::load() { + if(memory.size() == 0) { + memory.map(allocate(1024 * 1024, 0xff), 1024 * 1024); + } +} + +void BSXFlash::unload() { + memory.reset(); +} + +void BSXFlash::power() { + reset(); +} + +void BSXFlash::reset() { + regs.command = 0; + regs.write_old = 0x00; + regs.write_new = 0x00; + + regs.flash_enable = false; + regs.read_enable = false; + regs.write_enable = false; + memory.write_protect(!regs.write_enable); +} + +unsigned BSXFlash::size() const { + return memory.size(); +} + +uint8 BSXFlash::read(unsigned addr) { + if(addr == 0x0002) { + if(regs.flash_enable) return 0x80; + } + + if(addr == 0x5555) { + if(regs.flash_enable) return 0x80; + } + + if(regs.read_enable && addr >= 0xff00 && addr <= 0xff13) { + //read flash cartridge vendor information + switch(addr - 0xff00) { + case 0x00: return 0x4d; + case 0x01: return 0x00; + case 0x02: return 0x50; + case 0x03: return 0x00; + case 0x04: return 0x00; + case 0x05: return 0x00; + case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID) + case 0x07: return 0x00; + default: return 0x00; + } + } + + return memory.read(addr); +} + +void BSXFlash::write(unsigned addr, uint8 data) { + //there exist both read-only and read-write BS-X flash cartridges ... + //unfortunately, the vendor info is not stored inside memory dumps + //of BS-X flashcarts, so it is impossible to determine whether a + //given flashcart is writeable. + //however, it has been observed that LoROM-mapped BS-X carts always + //use read-write flashcarts, and HiROM-mapped BS-X carts always use + //read-only flashcarts. + //below is an unfortunately necessary workaround to this problem. + //if(cartridge.mapper() == Cartridge::BSCHiROM) return; + + if((addr & 0xff0000) == 0) { + regs.write_old = regs.write_new; + regs.write_new = data; + + if(regs.write_enable && regs.write_old == regs.write_new) { + return memory.write(addr, data); + } + } else { + if(regs.write_enable) { + return memory.write(addr, data); + } + } + + if(addr == 0x0000) { + regs.command <<= 8; + regs.command |= data; + + if((regs.command & 0xffff) == 0x38d0) { + regs.flash_enable = true; + regs.read_enable = true; + } + } + + if(addr == 0x2aaa) { + regs.command <<= 8; + regs.command |= data; + } + + if(addr == 0x5555) { + regs.command <<= 8; + regs.command |= data; + + if((regs.command & 0xffffff) == 0xaa5570) { + regs.write_enable = false; + } + + if((regs.command & 0xffffff) == 0xaa55a0) { + regs.write_old = 0x00; + regs.write_new = 0x00; + regs.flash_enable = true; + regs.write_enable = true; + } + + if((regs.command & 0xffffff) == 0xaa55f0) { + regs.flash_enable = false; + regs.read_enable = false; + regs.write_enable = false; + } + + memory.write_protect(!regs.write_enable); + } +} + +#endif diff --git a/snes/chip/bsx/flash/flash.hpp b/snes/chip/bsx/flash/flash.hpp new file mode 100755 index 00000000..353bef19 --- /dev/null +++ b/snes/chip/bsx/flash/flash.hpp @@ -0,0 +1,27 @@ +class BSXFlash : public Memory { +public: + MappedRAM memory; + + void init(); + void load(); + void unload(); + void power(); + void reset(); + + unsigned size() const; + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); + +private: + struct { + unsigned command; + uint8 write_old; + uint8 write_new; + + bool flash_enable; + bool read_enable; + bool write_enable; + } regs; +}; + +extern BSXFlash bsxflash; diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp new file mode 100755 index 00000000..7bfd13fb --- /dev/null +++ b/snes/chip/bsx/satellaview/satellaview.cpp @@ -0,0 +1,143 @@ +#ifdef BSX_CPP + +BSXSatellaview bsxsatellaview; + +void BSXSatellaview::init() { +} + +void BSXSatellaview::load() { + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview }); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview }); +} + +void BSXSatellaview::unload() { +} + +void BSXSatellaview::power() { + reset(); +} + +void BSXSatellaview::reset() { + memset(®s, 0x00, sizeof regs); +} + +uint8 BSXSatellaview::mmio_read(unsigned addr) { + addr &= 0xffff; + + switch(addr) { + case 0x2188: return regs.r2188; + case 0x2189: return regs.r2189; + case 0x218a: return regs.r218a; + case 0x218c: return regs.r218c; + case 0x218e: return regs.r218e; + case 0x218f: return regs.r218f; + case 0x2190: return regs.r2190; + + case 0x2192: { + unsigned counter = regs.r2192_counter++; + if(regs.r2192_counter >= 18) regs.r2192_counter = 0; + + if(counter == 0) { + time_t rawtime; + time(&rawtime); + tm *t = localtime(&rawtime); + + regs.r2192_hour = t->tm_hour; + regs.r2192_minute = t->tm_min; + regs.r2192_second = t->tm_sec; + } + + switch(counter) { + case 0: return 0x00; //??? + case 1: return 0x00; //??? + case 2: return 0x00; //??? + case 3: return 0x00; //??? + case 4: return 0x00; //??? + case 5: return 0x01; + case 6: return 0x01; + case 7: return 0x00; + case 8: return 0x00; + case 9: return 0x00; + case 10: return regs.r2192_second; + case 11: return regs.r2192_minute; + case 12: return regs.r2192_hour; + case 13: return 0x00; //??? + case 14: return 0x00; //??? + case 15: return 0x00; //??? + case 16: return 0x00; //??? + case 17: return 0x00; //??? + } + } break; + + case 0x2193: return regs.r2193 & ~0x0c; + case 0x2194: return regs.r2194; + case 0x2196: return regs.r2196; + case 0x2197: return regs.r2197; + case 0x2199: return regs.r2199; + } + + return cpu.regs.mdr; +} + +void BSXSatellaview::mmio_write(unsigned addr, uint8 data) { + addr &= 0xffff; + + switch(addr) { + case 0x2188: { + regs.r2188 = data; + } break; + + case 0x2189: { + regs.r2189 = data; + } break; + + case 0x218a: { + regs.r218a = data; + } break; + + case 0x218b: { + regs.r218b = data; + } break; + + case 0x218c: { + regs.r218c = data; + } break; + + case 0x218e: { + regs.r218e = data; + } break; + + case 0x218f: { + regs.r218e >>= 1; + regs.r218e = regs.r218f - regs.r218e; + regs.r218f >>= 1; + } break; + + case 0x2191: { + regs.r2191 = data; + regs.r2192_counter = 0; + } break; + + case 0x2192: { + regs.r2190 = 0x80; + } break; + + case 0x2193: { + regs.r2193 = data; + } break; + + case 0x2194: { + regs.r2194 = data; + } break; + + case 0x2197: { + regs.r2197 = data; + } break; + + case 0x2199: { + regs.r2199 = data; + } break; + } +} + +#endif diff --git a/snes/chip/bsx/satellaview/satellaview.hpp b/snes/chip/bsx/satellaview/satellaview.hpp new file mode 100755 index 00000000..0f99acbd --- /dev/null +++ b/snes/chip/bsx/satellaview/satellaview.hpp @@ -0,0 +1,26 @@ +class BSXSatellaview { +public: + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + +private: + struct { + uint8 r2188, r2189, r218a, r218b; + uint8 r218c, r218d, r218e, r218f; + uint8 r2190, r2191, r2192, r2193; + uint8 r2194, r2195, r2196, r2197; + uint8 r2198, r2199, r219a, r219b; + uint8 r219c, r219d, r219e, r219f; + + uint8 r2192_counter; + uint8 r2192_hour, r2192_minute, r2192_second; + } regs; +}; + +extern BSXSatellaview bsxsatellaview; diff --git a/snes/chip/chip.hpp b/snes/chip/chip.hpp new file mode 100755 index 00000000..37be5782 --- /dev/null +++ b/snes/chip/chip.hpp @@ -0,0 +1,28 @@ +struct Coprocessor : Processor { + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_cpu(); +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void Coprocessor::step(unsigned clocks) { + clock += clocks * (uint64)cpu.frequency; +} + +void Coprocessor::synchronize_cpu() { + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); +} diff --git a/snes/chip/hitachidsp/hitachidsp.cpp b/snes/chip/hitachidsp/hitachidsp.cpp new file mode 100755 index 00000000..62f4bfa2 --- /dev/null +++ b/snes/chip/hitachidsp/hitachidsp.cpp @@ -0,0 +1,79 @@ +#include + +#define HITACHIDSP_CPP +namespace SNES { + +#include "memory.cpp" +#include "opcodes.cpp" +#include "registers.cpp" +#include "serialization.cpp" +HitachiDSP hitachidsp; + +void HitachiDSP::Enter() { hitachidsp.enter(); } + +void HitachiDSP::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + switch(state) { + case State::Idle: + step(1); + break; + case State::DMA: + for(unsigned n = 0; n < regs.dma_length; n++) { + bus.write(regs.dma_target + n, bus.read(regs.dma_source + n)); + step(2); + } + state = State::Idle; + break; + case State::Execute: + unsigned offset = regs.program_offset + regs.pc * 2; + opcode = bus_read(offset + 0) << 0; + opcode |= bus_read(offset + 1) << 8; + regs.pc = (regs.pc & 0xffff00) | ((regs.pc + 1) & 0x0000ff); + exec(); + step(1); + break; + } + + synchronize_cpu(); + } +} + +void HitachiDSP::init() { +} + +void HitachiDSP::load() { +} + +void HitachiDSP::unload() { +} + +void HitachiDSP::power() { + reset(); +} + +void HitachiDSP::reset() { + create(HitachiDSP::Enter, frequency); + state = State::Idle; + + regs.n = 0; + regs.z = 0; + regs.c = 0; + + regs.dma_source = 0x000000; + regs.dma_length = 0x0000; + regs.dma_target = 0x000000; + regs.r1f48 = 0x00; + regs.program_offset = 0x000000; + regs.r1f4c = 0x00; + regs.page_number = 0x0000; + regs.program_counter = 0x00; + regs.r1f50 = 0x33; + regs.r1f51 = 0x00; + regs.r1f52 = 0x01; +} + +} diff --git a/snes/chip/hitachidsp/hitachidsp.hpp b/snes/chip/hitachidsp/hitachidsp.hpp new file mode 100755 index 00000000..40853c02 --- /dev/null +++ b/snes/chip/hitachidsp/hitachidsp.hpp @@ -0,0 +1,48 @@ +//Hitachi HG51B169 + +class HitachiDSP : public Coprocessor { +public: + unsigned frequency; +//uint16 programROM[2][256]; + uint24 dataROM[1024]; + uint8 dataRAM[3072]; + uint24 stack[8]; + uint16 opcode; + enum class State : unsigned { Idle, DMA, Execute } state; + #include "registers.hpp" + + static void Enter(); + void enter(); + + void init(); + void load(); + void unload(); + void power(); + void reset(); + + //memory.cpp + uint8 bus_read(unsigned addr); + void bus_write(unsigned addr, uint8 data); + + uint8 rom_read(unsigned addr); + void rom_write(unsigned addr, uint8 data); + + uint8 dsp_read(unsigned addr); + void dsp_write(unsigned addr, uint8 data); + + //opcodes.cpp + void push(); + void pull(); + unsigned sa(); + unsigned ri(); + unsigned np(); + void exec(); + + //registers.cpp + unsigned reg_read(unsigned n) const; + void reg_write(unsigned n, unsigned data); + + void serialize(serializer&); +}; + +extern HitachiDSP hitachidsp; diff --git a/snes/chip/hitachidsp/memory.cpp b/snes/chip/hitachidsp/memory.cpp new file mode 100755 index 00000000..3c9c3af1 --- /dev/null +++ b/snes/chip/hitachidsp/memory.cpp @@ -0,0 +1,133 @@ +#ifdef HITACHIDSP_CPP + +uint8 HitachiDSP::bus_read(unsigned addr) { + if((addr & 0x408000) == 0x008000) return bus.read(addr); + return 0x00; +} + +void HitachiDSP::bus_write(unsigned addr, uint8 data) { + if((addr & 0x40e000) == 0x006000) return bus.write(addr, data); +} + +uint8 HitachiDSP::rom_read(unsigned addr) { + if(co_active() == cpu.thread) { + if(state == State::Idle) return cartridge.rom.read(addr); + if((addr & 0x40ffe0) == 0x00ffe0) return regs.vector[addr & 0x1f]; + return cpu.regs.mdr; + } + if(co_active() == hitachidsp.thread) { + return cartridge.rom.read(addr); + } + return cpu.regs.mdr; +} + +void HitachiDSP::rom_write(unsigned addr, uint8 data) { +} + +uint8 HitachiDSP::dsp_read(unsigned addr) { + addr &= 0x1fff; + + //Data RAM + if((addr >= 0x0000 && addr <= 0x0bff) || (addr >= 0x1000 && addr <= 0x1bff)) { + return dataRAM[addr & 0x0fff]; + } + + //MMIO + switch(addr) { + case 0x1f40: return regs.dma_source >> 0; + case 0x1f41: return regs.dma_source >> 8; + case 0x1f42: return regs.dma_source >> 16; + case 0x1f43: return regs.dma_length >> 0; + case 0x1f44: return regs.dma_length >> 8; + case 0x1f45: return regs.dma_target >> 0; + case 0x1f46: return regs.dma_target >> 8; + case 0x1f47: return regs.dma_target >> 16; + case 0x1f48: return regs.r1f48; + case 0x1f49: return regs.program_offset >> 0; + case 0x1f4a: return regs.program_offset >> 8; + case 0x1f4b: return regs.program_offset >> 16; + case 0x1f4c: return regs.r1f4c; + case 0x1f4d: return regs.page_number >> 0; + case 0x1f4e: return regs.page_number >> 8; + case 0x1f4f: return regs.program_counter; + case 0x1f50: return regs.r1f50; + case 0x1f51: return regs.r1f51; + case 0x1f52: return regs.r1f52; + case 0x1f53: case 0x1f54: case 0x1f55: case 0x1f56: + case 0x1f57: case 0x1f58: case 0x1f59: case 0x1f5a: + case 0x1f5b: case 0x1f5c: case 0x1f5d: case 0x1f5e: + case 0x1f5f: return ((state != State::Idle) << 6) | ((state == State::Idle) << 1); + } + + //Vector + if(addr >= 0x1f60 && addr <= 0x1f7f) { + return regs.vector[addr & 0x1f]; + } + + //GPRs + if((addr >= 0x1f80 && addr <= 0x1faf) || (addr >= 0x1fc0 && addr <= 0x1fef)) { + unsigned index = (addr & 0x3f) / 3; //0..15 + unsigned shift = ((addr & 0x3f) % 3) * 8; //0, 8, 16 + return regs.gpr[index] >> shift; + } + + return 0x00; +} + +void HitachiDSP::dsp_write(unsigned addr, uint8 data) { + addr &= 0x1fff; + + //Data RAM + if((addr >= 0x0000 && addr <= 0x0bff) || (addr >= 0x1000 && addr <= 0x1bff)) { + dataRAM[addr & 0x0fff] = data; + return; + } + + //MMIO + switch(addr) { + case 0x1f40: regs.dma_source = (regs.dma_source & 0xffff00) | (data << 0); return; + case 0x1f41: regs.dma_source = (regs.dma_source & 0xff00ff) | (data << 8); return; + case 0x1f42: regs.dma_source = (regs.dma_source & 0x00ffff) | (data << 16); return; + case 0x1f43: regs.dma_length = (regs.dma_length & 0xff00) | (data << 0); return; + case 0x1f44: regs.dma_length = (regs.dma_length & 0x00ff) | (data << 8); return; + case 0x1f45: regs.dma_target = (regs.dma_target & 0xffff00) | (data << 0); return; + case 0x1f46: regs.dma_target = (regs.dma_target & 0xff00ff) | (data << 8); return; + case 0x1f47: regs.dma_target = (regs.dma_target & 0x00ffff) | (data << 16); + if(state == State::Idle) state = State::DMA; + return; + case 0x1f48: regs.r1f48 = data & 0x01; return; + case 0x1f49: regs.program_offset = (regs.program_offset & 0xffff00) | (data << 0); return; + case 0x1f4a: regs.program_offset = (regs.program_offset & 0xff00ff) | (data << 8); return; + case 0x1f4b: regs.program_offset = (regs.program_offset & 0x00ffff) | (data << 16); return; + case 0x1f4c: regs.r1f4c = data & 0x03; return; + case 0x1f4d: regs.page_number = (regs.page_number & 0x7f00) | ((data & 0xff) << 0); return; + case 0x1f4e: regs.page_number = (regs.page_number & 0x00ff) | ((data & 0x7f) << 8); return; + case 0x1f4f: regs.program_counter = data; + if(state == State::Idle) { + regs.pc = regs.page_number * 256 + regs.program_counter; + state = State::Execute; + } + return; + case 0x1f50: regs.r1f50 = data & 0x77; return; + case 0x1f51: regs.r1f51 = data & 0x01; return; + case 0x1f52: regs.r1f52 = data & 0x01; return; + } + + //Vector + if(addr >= 0x1f60 && addr <= 0x1f7f) { + regs.vector[addr & 0x1f] = data; + return; + } + + //GPRs + if((addr >= 0x1f80 && addr <= 0x1faf) || (addr >= 0x1fc0 && addr <= 0x1fef)) { + unsigned index = (addr & 0x3f) / 3; + switch((addr & 0x3f) % 3) { + case 0: regs.gpr[index] = (regs.gpr[index] & 0xffff00) | (data << 0); return; + case 1: regs.gpr[index] = (regs.gpr[index] & 0xff00ff) | (data << 8); return; + case 2: regs.gpr[index] = (regs.gpr[index] & 0x00ffff) | (data << 16); return; + } + } +} + +#endif diff --git a/snes/chip/hitachidsp/opcodes.cpp b/snes/chip/hitachidsp/opcodes.cpp new file mode 100755 index 00000000..6fc9d2d7 --- /dev/null +++ b/snes/chip/hitachidsp/opcodes.cpp @@ -0,0 +1,356 @@ +#ifdef HITACHIDSP_CPP + +void HitachiDSP::push() { + stack[7] = stack[6]; + stack[6] = stack[5]; + stack[5] = stack[4]; + stack[4] = stack[3]; + stack[3] = stack[2]; + stack[2] = stack[1]; + stack[1] = stack[0]; + stack[0] = regs.pc; +} + +void HitachiDSP::pull() { + regs.pc = stack[0]; + stack[0] = stack[1]; + stack[1] = stack[2]; + stack[2] = stack[3]; + stack[3] = stack[4]; + stack[4] = stack[5]; + stack[5] = stack[6]; + stack[6] = stack[7]; + stack[7] = 0x0000; +} + +//Shift-A: math opcodes can shift A register prior to ALU operation +unsigned HitachiDSP::sa() { + switch(opcode & 0x0300) { default: + case 0x0000: return regs.a << 0; + case 0x0100: return regs.a << 1; + case 0x0200: return regs.a << 8; + case 0x0300: return regs.a << 16; + } +} + +//Register-or-Immediate: most opcodes can load from a register or immediate +unsigned HitachiDSP::ri() { + if(opcode & 0x0400) return opcode & 0xff; + return reg_read(opcode & 0xff); +} + +//New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes) +unsigned HitachiDSP::np() { + if(opcode & 0x0200) return (regs.p << 8) | (opcode & 0xff); + return (regs.pc & 0xffff00) | (opcode & 0xff); +} + +void HitachiDSP::exec() { + if((opcode & 0xffff) == 0x0000) { + //0000 0000 0000 0000 + //nop + } + + else if((opcode & 0xdd00) == 0x0800) { + //00.0 10.0 .... .... + //jump i + if(opcode & 0x2000) push(); + regs.pc = np(); + } + + else if((opcode & 0xdd00) == 0x0c00) { + //00.0 11.0 .... .... + //jumpeq i + if(regs.z) { + if(opcode & 0x2000) push(); + regs.pc = np(); + } + } + + else if((opcode & 0xdd00) == 0x1000) { + //00.1 00.0 .... .... + //jumpge i + if(regs.c) { + if(opcode & 0x2000) push(); + regs.pc = np(); + } + } + + else if((opcode & 0xdd00) == 0x1400) { + //00.1 01.0 .... .... + //jumpmi i + if(regs.n) { + if(opcode & 0x2000) push(); + regs.pc = np(); + } + } + + else if((opcode & 0xffff) == 0x1c00) { + //0001 1100 0000 0000 + //loop? + } + + else if((opcode & 0xfffe) == 0x2500) { + //0010 0101 0000 000. + //skiplt/skipge + if(regs.c == (opcode & 1)) regs.pc++; + } + + else if((opcode & 0xfffe) == 0x2600) { + //0010 0110 0000 000. + //skipne/skipeq + if(regs.z == (opcode & 1)) regs.pc++; + } + + else if((opcode & 0xfffe) == 0x2700) { + //0010 0111 0000 000. + //skipmi/skippl + if(regs.n == (opcode & 1)) regs.pc++; + } + + else if((opcode & 0xffff) == 0x3c00) { + //0011 1100 0000 0000 + //ret + pull(); + } + + else if((opcode & 0xffff) == 0x4000) { + //0100 0000 0000 0000 + //rdbus + regs.busdata = bus_read(regs.busaddr++); + } + + else if((opcode & 0xf800) == 0x4800) { + //0100 1... .... .... + //cmpr a<= 0; + } + + else if((opcode & 0xf800) == 0x5000) { + //0101 0... .... .... + //cmp a<= 0; + } + + else if((opcode & 0xfb00) == 0x5900) { + //0101 1.01 .... .... + //sxb + regs.a = (int8)ri(); + } + + else if((opcode & 0xfb00) == 0x5a00) { + //0101 1.10 .... .... + //sxw + regs.a = (int16)ri(); + } + + else if((opcode & 0xfb00) == 0x6000) { + //0110 0.00 .... .... + //ld a,ri + regs.a = ri(); + } + + else if((opcode & 0xfb00) == 0x6100) { + //0110 0.01 .... .... + //ld ?,ri + } + + else if((opcode & 0xfb00) == 0x6300) { + //0110 0.11 .... .... + //ld p,ri + regs.p = ri(); + } + + else if((opcode & 0xfb00) == 0x6800) { + //0110 1.00 .... .... + //rdraml + uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); + if(target < 0xc00) regs.ramdata = (regs.ramdata & 0xffff00) | (dataRAM[target] << 0); + } + + else if((opcode & 0xfb00) == 0x6900) { + //0110 1.01 .... .... + //rdramh + uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); + if(target < 0xc00) regs.ramdata = (regs.ramdata & 0xff00ff) | (dataRAM[target] << 8); + } + + else if((opcode & 0xfb00) == 0x6a00) { + //0110 1.10 .... .... + //rdramb + uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); + if(target < 0xc00) regs.ramdata = (regs.ramdata & 0x00ffff) | (dataRAM[target] << 16); + } + + else if((opcode & 0xffff) == 0x7000) { + //0111 0000 0000 0000 + //rdrom + regs.romdata = dataROM[regs.a & 0x3ff]; + } + + else if((opcode & 0xff00) == 0x7c00) { + //0111 1100 .... .... + //ld pl,i + regs.p = (regs.p & 0xff00) | ((opcode & 0xff) << 0); + } + + else if((opcode & 0xff00) == 0x7d00) { + //0111 1101 .... .... + //ld ph,i + regs.p = (regs.p & 0x00ff) | ((opcode & 0xff) << 8); + } + + else if((opcode & 0xf800) == 0x8000) { + //1000 0... .... .... + //add a< 0xffffff; + } + + else if((opcode & 0xf800) == 0x8800) { + //1000 1... .... .... + //subr a<= 0; + } + + else if((opcode & 0xf800) == 0x9000) { + //1001 0... .... .... + //sub a<= 0; + } + + else if((opcode & 0xfb00) == 0x9800) { + //1001 1.00 .... .... + //mul a,ri + int64 x = (int24)regs.a; + int64 y = (int24)ri(); + x *= y; + regs.accl = x >> 0ull; + regs.acch = x >> 24ull; + regs.n = regs.acch & 0x800000; + regs.z = x == 0; + } + + else if((opcode & 0xf800) == 0xa800) { + //1010 1... .... .... + //xor a<> ri(); + regs.n = regs.a & 0x800000; + regs.z = regs.a == 0; + } + + else if((opcode & 0xfb00) == 0xc800) { + //1100 1.00 .... .... + //asr a,ri + regs.a = (int24)regs.a >> ri(); + regs.n = regs.a & 0x800000; + regs.z = regs.a == 0; + } + + else if((opcode & 0xfb00) == 0xd000) { + //1101 0.00 .... .... + //ror a,ri + uint24 length = ri(); + regs.a = (regs.a >> length) | (regs.a << (24 - length)); + regs.n = regs.a & 0x800000; + regs.z = regs.a == 0; + } + + else if((opcode & 0xfb00) == 0xd800) { + //1101 1.00 .... .... + //shl a,ri + regs.a = regs.a << ri(); + regs.n = regs.a & 0x800000; + regs.z = regs.a == 0; + } + + else if((opcode & 0xff00) == 0xe000) { + //1110 0000 .... .... + //st r,a + reg_write(opcode & 0xff, regs.a); + } + + else if((opcode & 0xfb00) == 0xe800) { + //1110 1.00 .... .... + //wrraml + uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); + if(target < 0xc00) dataRAM[target] = regs.ramdata >> 0; + } + + else if((opcode & 0xfb00) == 0xe900) { + //1110 1.01 .... .... + //wrramh + uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); + if(target < 0xc00) dataRAM[target] = regs.ramdata >> 8; + } + + else if((opcode & 0xfb00) == 0xea00) { + //1110 1.10 .... .... + //wrramb + uint24 target = ri() + (opcode & 0x0400 ? regs.ramaddr : (uint24)0); + if(target < 0xc00) dataRAM[target] = regs.ramdata >> 16; + } + + else if((opcode & 0xff00) == 0xf000) { + //1111 0000 .... .... + //swap a,r + uint24 source = reg_read(opcode & 0xff); + uint24 target = regs.a; + regs.a = source; + reg_write(opcode & 0xff, target); + } + + else if((opcode & 0xffff) == 0xfc00) { + //1111 1100 0000 0000 + //halt + state = State::Idle; + } + + else { + print("Hitachi DSP: invalid opcode @ ", hex<4>(regs.pc - 1), " = ", hex<4>(opcode), "\n"); + state = State::Idle; + } +} + +#endif diff --git a/snes/chip/hitachidsp/registers.cpp b/snes/chip/hitachidsp/registers.cpp new file mode 100755 index 00000000..396bdf3e --- /dev/null +++ b/snes/chip/hitachidsp/registers.cpp @@ -0,0 +1,78 @@ +#ifdef HITACHIDSP_CPP + +unsigned HitachiDSP::reg_read(unsigned n) const { + switch(n) { + case 0x00: return regs.a; + case 0x01: return regs.acch; + case 0x02: return regs.accl; + case 0x03: return regs.busdata; + case 0x08: return regs.romdata; + case 0x0c: return regs.ramdata; + case 0x13: return regs.busaddr; + case 0x1c: return regs.ramaddr; + case 0x50: return 0x000000; + case 0x51: return 0xffffff; + case 0x52: return 0x00ff00; + case 0x53: return 0xff0000; + case 0x54: return 0x00ffff; + case 0x55: return 0xffff00; + case 0x56: return 0x800000; + case 0x57: return 0x7fffff; + case 0x58: return 0x008000; + case 0x59: return 0x007fff; + case 0x5a: return 0xff7fff; + case 0x5b: return 0xffff7f; + case 0x5c: return 0x010000; + case 0x5d: return 0xfeffff; + case 0x5e: return 0x000100; + case 0x5f: return 0x00feff; + case 0x60: return regs.gpr[ 0]; + case 0x61: return regs.gpr[ 1]; + case 0x62: return regs.gpr[ 2]; + case 0x63: return regs.gpr[ 3]; + case 0x64: return regs.gpr[ 4]; + case 0x65: return regs.gpr[ 5]; + case 0x66: return regs.gpr[ 6]; + case 0x67: return regs.gpr[ 7]; + case 0x68: return regs.gpr[ 8]; + case 0x69: return regs.gpr[ 9]; + case 0x6a: return regs.gpr[10]; + case 0x6b: return regs.gpr[11]; + case 0x6c: return regs.gpr[12]; + case 0x6d: return regs.gpr[13]; + case 0x6e: return regs.gpr[14]; + case 0x6f: return regs.gpr[15]; + } + return 0x000000; +} + +void HitachiDSP::reg_write(unsigned n, unsigned data) { + switch(n) { + case 0x00: regs.a = data; return; + case 0x01: regs.acch = data; return; + case 0x02: regs.accl = data; return; + case 0x03: regs.busdata = data; return; + case 0x08: regs.romdata = data; return; + case 0x0c: regs.ramdata = data; return; + case 0x13: regs.busaddr = data; return; + case 0x1c: regs.ramaddr = data; return; + case 0x60: regs.gpr[ 0] = data; return; + case 0x61: regs.gpr[ 1] = data; return; + case 0x62: regs.gpr[ 2] = data; return; + case 0x63: regs.gpr[ 3] = data; return; + case 0x64: regs.gpr[ 4] = data; return; + case 0x65: regs.gpr[ 5] = data; return; + case 0x66: regs.gpr[ 6] = data; return; + case 0x67: regs.gpr[ 7] = data; return; + case 0x68: regs.gpr[ 8] = data; return; + case 0x69: regs.gpr[ 9] = data; return; + case 0x6a: regs.gpr[10] = data; return; + case 0x6b: regs.gpr[11] = data; return; + case 0x6c: regs.gpr[12] = data; return; + case 0x6d: regs.gpr[13] = data; return; + case 0x6e: regs.gpr[14] = data; return; + case 0x6f: regs.gpr[15] = data; return; + } +} + +#endif diff --git a/snes/chip/hitachidsp/registers.hpp b/snes/chip/hitachidsp/registers.hpp new file mode 100755 index 00000000..73d2370f --- /dev/null +++ b/snes/chip/hitachidsp/registers.hpp @@ -0,0 +1,31 @@ +struct Registers { + uint24 pc; + uint16 p; + bool n; + bool z; + bool c; + + uint24 a; + uint24 acch; + uint24 accl; + uint24 busdata; + uint24 romdata; + uint24 ramdata; + uint24 busaddr; + uint24 ramaddr; + uint24 gpr[16]; + + //MMIO + uint24 dma_source; //$1f40-$1f42 + uint24 dma_length; //$1f43-$1f44 + uint24 dma_target; //$1f45-$1f47 + uint8 r1f48; //$1f48 + uint24 program_offset; //$1f49-$1f4b + uint8 r1f4c; //$1f4c + uint16 page_number; //$1f4d-$1f4e + uint8 program_counter; //$1f4f + uint8 r1f50; //$1f50 + uint8 r1f51; //$1f51 + uint8 r1f52; //$1f52 + uint8 vector[32]; //$1f60-$1f7f +} regs; diff --git a/snes/chip/hitachidsp/serialization.cpp b/snes/chip/hitachidsp/serialization.cpp new file mode 100755 index 00000000..dc6d2d39 --- /dev/null +++ b/snes/chip/hitachidsp/serialization.cpp @@ -0,0 +1,41 @@ +#ifdef HITACHIDSP_CPP + +void HitachiDSP::serialize(serializer &s) { + Processor::serialize(s); + + s.array(dataRAM); + for(auto &n : stack) s.integer(n); + s.integer(opcode); + s.integer((unsigned&)state); + + s.integer(regs.pc); + s.integer(regs.p); + s.integer(regs.n); + s.integer(regs.z); + s.integer(regs.c); + + s.integer(regs.a); + s.integer(regs.acch); + s.integer(regs.accl); + s.integer(regs.busdata); + s.integer(regs.romdata); + s.integer(regs.ramdata); + s.integer(regs.busaddr); + s.integer(regs.ramaddr); + for(auto &n : regs.gpr) s.integer(n); + + s.integer(regs.dma_source); + s.integer(regs.dma_length); + s.integer(regs.dma_target); + s.integer(regs.r1f48); + s.integer(regs.program_offset); + s.integer(regs.r1f4c); + s.integer(regs.page_number); + s.integer(regs.program_counter); + s.integer(regs.r1f50); + s.integer(regs.r1f51); + s.integer(regs.r1f52); + s.array(regs.vector); +} + +#endif diff --git a/snes/chip/icd2/icd2.cpp b/snes/chip/icd2/icd2.cpp new file mode 100755 index 00000000..c8a82df3 --- /dev/null +++ b/snes/chip/icd2/icd2.cpp @@ -0,0 +1,77 @@ +#include + +#define ICD2_CPP +namespace SNES { + +#include "interface/interface.cpp" +#include "mmio/mmio.cpp" +#include "serialization.cpp" +ICD2 icd2; + +void ICD2::Enter() { icd2.enter(); } + +void ICD2::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + GameBoy::system.runtosave(); + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(r6003 & 0x80) { + GameBoy::system.run(); + step(GameBoy::system.clocks_executed); + GameBoy::system.clocks_executed = 0; + } else { //DMG halted + audio.coprocessor_sample(0x0000, 0x0000); + step(1); + } + synchronize_cpu(); + } +} + +void ICD2::init() { +} + +void ICD2::load() { +} + +void ICD2::unload() { +} + +void ICD2::power() { + audio.coprocessor_enable(true); + audio.coprocessor_frequency(4 * 1024 * 1024); + + reset(); +} + +void ICD2::reset() { + create(ICD2::Enter, cpu.frequency / 5); + + r6000_ly = 0x00; + r6000_row = 0x00; + r6003 = 0x00; + r6004 = 0xff; + r6005 = 0xff; + r6006 = 0xff; + r6007 = 0xff; + for(unsigned n = 0; n < 16; n++) r7000[n] = 0x00; + r7800 = 0x0000; + mlt_req = 0; + + for(auto &n : lcd.buffer) n = 0; + for(auto &n : lcd.output) n = 0; + lcd.row = 0; + + packetsize = 0; + joyp_id = 3; + joyp15lock = 0; + joyp14lock = 0; + pulselock = true; + + GameBoy::interface = this; + GameBoy::system.init(); + GameBoy::system.power(); +} + +} diff --git a/snes/chip/icd2/icd2.hpp b/snes/chip/icd2/icd2.hpp new file mode 100755 index 00000000..511ca1cf --- /dev/null +++ b/snes/chip/icd2/icd2.hpp @@ -0,0 +1,24 @@ +class ICD2 : public GameBoy::Interface, public Coprocessor { +public: + unsigned revision; + + static void Enter(); + void enter(); + + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); + + void serialize(serializer&); + +private: + #include "interface/interface.hpp" + #include "mmio/mmio.hpp" +}; + +extern ICD2 icd2; diff --git a/snes/chip/icd2/interface/interface.cpp b/snes/chip/icd2/interface/interface.cpp new file mode 100755 index 00000000..8a188bc3 --- /dev/null +++ b/snes/chip/icd2/interface/interface.cpp @@ -0,0 +1,115 @@ +#ifdef ICD2_CPP + +//called on rendered lines 0-143 (not on Vblank lines 144-153) +void ICD2::lcdScanline() { + if((GameBoy::lcd.status.ly & 7) == 0) { + lcd.row = (lcd.row + 1) & 3; + } + + unsigned offset = (lcd.row * 160 * 8) + ((GameBoy::lcd.status.ly & 7) * 160); + memcpy(lcd.buffer + offset, GameBoy::lcd.screen + GameBoy::lcd.status.ly * 160, 160 * sizeof(uint16)); +} + +void ICD2::joypWrite(bool p15, bool p14) { + //joypad handling + if(p15 == 1 && p14 == 1) { + if(joyp15lock == 0 && joyp14lock == 0) { + joyp15lock = 1; + joyp14lock = 1; + joyp_id = (joyp_id + 1) & 3; + } + } + + if(p15 == 0 && p14 == 1) joyp15lock = 0; + if(p15 == 1 && p14 == 0) joyp14lock = 0; + + //packet handling + if(p15 == 0 && p14 == 0) { //pulse + pulselock = false; + packetoffset = 0; + bitoffset = 0; + strobelock = true; + packetlock = false; + return; + } + + if(pulselock) return; + + if(p15 == 1 && p14 == 1) { + strobelock = false; + return; + } + + if(strobelock) { + if(p15 == 1 || p14 == 1) { //malformed packet + packetlock = false; + pulselock = true; + bitoffset = 0; + packetoffset = 0; + } else { + return; + } + } + + //p15:1, p14:0 = 0 + //p15:0, p14:1 = 1 + bool bit = (p15 == 0); + strobelock = true; + + if(packetlock) { + if(p15 == 1 && p14 == 0) { + if((joyp_packet[0] >> 3) == 0x11) { + mlt_req = joyp_packet[1] & 3; + if(mlt_req == 2) mlt_req = 3; + joyp_id = 0; + } + + if(packetsize < 64) packet[packetsize++] = joyp_packet; + packetlock = false; + pulselock = true; + } + return; + } + + bitdata = (bit << 7) | (bitdata >> 1); + if(++bitoffset < 8) return; + + bitoffset = 0; + joyp_packet[packetoffset] = bitdata; + if(++packetoffset < 16) return; + packetlock = true; +} + +void ICD2::videoRefresh(const uint16_t *data) { +} + +void ICD2::audioSample(int16_t center, int16_t left, int16_t right) { + audio.coprocessor_sample(left, right); +} + +bool ICD2::inputPoll(unsigned id) { + GameBoy::cpu.status.mlt_req = joyp_id & mlt_req; + + unsigned data = 0x00; + switch(joyp_id & mlt_req) { + case 0: data = ~r6004; break; + case 1: data = ~r6005; break; + case 2: data = ~r6006; break; + case 3: data = ~r6007; break; + } + + switch((GameBoy::Input)id) { + case GameBoy::Input::Start: return data & 0x80; + case GameBoy::Input::Select: return data & 0x40; + case GameBoy::Input::B: return data & 0x20; + case GameBoy::Input::A: return data & 0x10; + case GameBoy::Input::Down: return data & 0x08; + case GameBoy::Input::Up: return data & 0x04; + case GameBoy::Input::Left: return data & 0x02; + case GameBoy::Input::Right: return data & 0x01; + } + + return 0; +} + +#endif diff --git a/snes/chip/icd2/interface/interface.hpp b/snes/chip/icd2/interface/interface.hpp new file mode 100755 index 00000000..1c157836 --- /dev/null +++ b/snes/chip/icd2/interface/interface.hpp @@ -0,0 +1,22 @@ +void lcdScanline(); +void joypWrite(bool p15, bool p14); +void videoRefresh(const uint16_t *data); +void audioSample(int16_t center, int16_t left, int16_t right); +bool inputPoll(unsigned id); + +struct Packet { + uint8 data[16]; + uint8& operator[](unsigned addr) { return data[addr & 15]; } +}; +Packet packet[64]; +unsigned packetsize; + +unsigned joyp_id; +bool joyp15lock; +bool joyp14lock; +bool pulselock; +bool strobelock; +bool packetlock; +Packet joyp_packet; +uint8 packetoffset; +uint8 bitdata, bitoffset; diff --git a/snes/chip/icd2/mmio/mmio.cpp b/snes/chip/icd2/mmio/mmio.cpp new file mode 100755 index 00000000..0835c027 --- /dev/null +++ b/snes/chip/icd2/mmio/mmio.cpp @@ -0,0 +1,96 @@ +#ifdef ICD2_CPP + +//convert linear pixel data { 0x00, 0x55, 0xaa, 0xff } to 2bpp planar tiledata +void ICD2::render(const uint16 *source) { + memset(lcd.output, 0x00, 320 * sizeof(uint16)); + + for(unsigned y = 0; y < 8; y++) { + for(unsigned x = 0; x < 160; x++) { + unsigned pixel = *source++; + unsigned addr = y * 2 + (x / 8 * 16); + lcd.output[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7)); + lcd.output[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7)); + } + } +} + +uint8 ICD2::read(unsigned addr) { + addr &= 0xffff; + + //LY counter + if(addr == 0x6000) { + r6000_ly = GameBoy::lcd.status.ly; + r6000_row = lcd.row; + return r6000_ly; + } + + //command ready port + if(addr == 0x6002) { + bool data = packetsize > 0; + if(data) { + for(unsigned i = 0; i < 16; i++) r7000[i] = packet[0][i]; + packetsize--; + for(unsigned i = 0; i < packetsize; i++) packet[i] = packet[i + 1]; + } + return data; + } + + //ICD2 revision + if(addr == 0x600f) { + return 0x21; + } + + //command port + if((addr & 0xfff0) == 0x7000) { + return r7000[addr & 15]; + } + + //VRAM port + if(addr == 0x7800) { + uint8 data = lcd.output[r7800]; + r7800 = (r7800 + 1) % 320; + return data; + } + + return 0x00; +} + +void ICD2::write(unsigned addr, uint8 data) { + addr &= 0xffff; + + //VRAM port + if(addr == 0x6001) { + r6001 = data; + r7800 = 0; + + unsigned offset = (r6000_row - (4 - (r6001 - (r6000_ly & 3)))) & 3; + render(lcd.buffer + offset * 160 * 8); + + return; + } + + //control port + //d7: 0 = halt, 1 = reset + //d5,d4: 0 = 1-player, 1 = 2-player, 2 = 4-player, 3 = ??? + //d1,d0: 0 = frequency divider (clock rate adjust) + if(addr == 0x6003) { + if((r6003 & 0x80) == 0x00 && (data & 0x80) == 0x80) { + reset(); + } + switch(data & 3) { + case 0: frequency = cpu.frequency / 4; break; //fast (glitchy, even on real hardware) + case 1: frequency = cpu.frequency / 5; break; //normal + case 2: frequency = cpu.frequency / 7; break; //slow + case 3: frequency = cpu.frequency / 9; break; //very slow + } + r6003 = data; + return; + } + + if(addr == 0x6004) { r6004 = data; return; } //joypad 1 + if(addr == 0x6005) { r6005 = data; return; } //joypad 2 + if(addr == 0x6006) { r6006 = data; return; } //joypad 3 + if(addr == 0x6007) { r6007 = data; return; } //joypad 4 +} + +#endif diff --git a/snes/chip/icd2/mmio/mmio.hpp b/snes/chip/icd2/mmio/mmio.hpp new file mode 100755 index 00000000..fdd029de --- /dev/null +++ b/snes/chip/icd2/mmio/mmio.hpp @@ -0,0 +1,19 @@ +void render(const uint16 *source); + +uint8 r6000_ly; //SGB BIOS' cache of LY +uint8 r6000_row; //SGB BIOS' cache of ROW +uint8 r6001; //VRAM conversion +uint8 r6003; //control port +uint8 r6004; //joypad 1 +uint8 r6005; //joypad 2 +uint8 r6006; //joypad 3 +uint8 r6007; //joypad 4 +uint8 r7000[16]; //JOYP packet data +unsigned r7800; //VRAM offset +uint8 mlt_req; //number of active joypads + +struct LCD { + uint16 buffer[4 * 160 * 8]; //four tile rows of linear video data + uint16 output[320]; //one tile row of 2bpp video data + unsigned row; //active ICD2 rendering tile row +} lcd; diff --git a/snes/chip/icd2/serialization.cpp b/snes/chip/icd2/serialization.cpp new file mode 100755 index 00000000..5c31448e --- /dev/null +++ b/snes/chip/icd2/serialization.cpp @@ -0,0 +1,38 @@ +#ifdef ICD2_CPP + +void ICD2::serialize(serializer &s) { + Processor::serialize(s); + GameBoy::system.serialize_all(s); + + for(unsigned n = 0; n < 64; n++) s.array(packet[n].data); + s.integer(packetsize); + + s.integer(joyp_id); + s.integer(joyp15lock); + s.integer(joyp14lock); + s.integer(pulselock); + s.integer(strobelock); + s.integer(packetlock); + s.array(joyp_packet.data); + s.integer(packetoffset); + s.integer(bitdata); + s.integer(bitoffset); + + s.integer(r6000_ly); + s.integer(r6000_row); + s.integer(r6001); + s.integer(r6003); + s.integer(r6004); + s.integer(r6005); + s.integer(r6006); + s.integer(r6007); + s.array(r7000); + s.integer(r7800); + s.integer(mlt_req); + + s.array(lcd.buffer); + s.array(lcd.output); + s.integer(lcd.row); +} + +#endif diff --git a/snes/chip/link/link.cpp b/snes/chip/link/link.cpp new file mode 100755 index 00000000..a5736933 --- /dev/null +++ b/snes/chip/link/link.cpp @@ -0,0 +1,60 @@ +#include + +#define LINK_HPP +namespace SNES { + +Link link; + +void Link::Enter() { link.enter(); } + +void Link::enter() { + while(true) { + cpu.synchronize_coprocessors(); + unsigned clocks = 1; + if(link_run) clocks = link_run(); + step(clocks); + synchronize_cpu(); + } +} + +void Link::init() { +} + +void Link::load() { + if(opened()) close(); + string basename = interface->path(Cartridge::Slot::Base, ""); + string name = program != "" ? program : notdir(basename); + string path = dir(basename); + if(open(name, path)) { + link_power = sym("link_power"); + link_reset = sym("link_reset"); + link_run = sym("link_run" ); + link_read = sym("link_read" ); + link_write = sym("link_write"); + } +} + +void Link::unload() { + if(opened()) close(); +} + +void Link::power() { + if(link_power) link_power(); + create(Link::Enter, frequency); +} + +void Link::reset() { + if(link_reset) link_reset(); + create(Link::Enter, frequency); +} + +uint8 Link::read(unsigned addr) { + if(link_read) return link_read(addr); + return cpu.regs.mdr; +} + +void Link::write(unsigned addr, uint8 data) { + if(link_write) return link_write(addr, data); +} + +} diff --git a/snes/chip/link/link.hpp b/snes/chip/link/link.hpp new file mode 100755 index 00000000..1898fa02 --- /dev/null +++ b/snes/chip/link/link.hpp @@ -0,0 +1,24 @@ +class Link : public Coprocessor, public library { +public: + string program; + + static void Enter(); + void enter(); + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); + +private: + function link_power; + function link_reset; + function link_run; + function link_read; + function link_write; +}; + +extern Link link; diff --git a/snes/chip/msu1/msu1.cpp b/snes/chip/msu1/msu1.cpp new file mode 100755 index 00000000..af19acea --- /dev/null +++ b/snes/chip/msu1/msu1.cpp @@ -0,0 +1,160 @@ +#include + +#define MSU1_CPP +namespace SNES { + +MSU1 msu1; + +#include "serialization.cpp" + +void MSU1::Enter() { msu1.enter(); } + +void MSU1::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + int16 left = 0, right = 0; + + if(mmio.audio_play) { + if(audiofile.open()) { + if(audiofile.end()) { + if(!mmio.audio_repeat) { + mmio.audio_play = false; + audiofile.seek(mmio.audio_offset = 8); + } else { + audiofile.seek(mmio.audio_offset = mmio.audio_loop_offset); + } + } else { + mmio.audio_offset += 4; + left = audiofile.readl(2); + right = audiofile.readl(2); + } + } else { + mmio.audio_play = false; + } + } + + left = sclamp<16>((double)left * (double)mmio.audio_volume / 255.0); + right = sclamp<16>((double)right * (double)mmio.audio_volume / 255.0); + + audio.coprocessor_sample(left, right); + step(1); + synchronize_cpu(); + } +} + +void MSU1::init() { +} + +void MSU1::load() { + if(datafile.open()) datafile.close(); + datafile.open(interface->path(Cartridge::Slot::Base, ".msu"), file::mode::read); +} + +void MSU1::unload() { + if(datafile.open()) datafile.close(); +} + +void MSU1::power() { + audio.coprocessor_enable(true); + audio.coprocessor_frequency(44100.0); + + reset(); +} + +void MSU1::reset() { + create(MSU1::Enter, 44100); + + mmio.data_offset = 0; + mmio.audio_offset = 0; + mmio.audio_track = 0; + mmio.audio_volume = 255; + mmio.data_busy = true; + mmio.audio_busy = true; + mmio.audio_repeat = false; + mmio.audio_play = false; +} + +uint8 MSU1::mmio_read(unsigned addr) { + addr &= 0xffff; + + if(addr == 0x2000) { + return (mmio.data_busy << 7) + | (mmio.audio_busy << 6) + | (mmio.audio_repeat << 5) + | (mmio.audio_play << 4) + | (Revision << 0); + } + + if(addr == 0x2001) { + if(mmio.data_busy) return 0x00; + mmio.data_offset++; + if(datafile.open()) return datafile.read(); + return 0x00; + } + + if(addr == 0x2002) return 'S'; + if(addr == 0x2003) return '-'; + if(addr == 0x2004) return 'M'; + if(addr == 0x2005) return 'S'; + if(addr == 0x2006) return 'U'; + if(addr == 0x2007) return '0' + Revision; + + return 0x00; +} + +void MSU1::mmio_write(unsigned addr, uint8 data) { + addr &= 0xffff; + + if(addr == 0x2000) { + mmio.data_offset = (mmio.data_offset & 0xffffff00) | (data << 0); + } + + if(addr == 0x2001) { + mmio.data_offset = (mmio.data_offset & 0xffff00ff) | (data << 8); + } + + if(addr == 0x2002) { + mmio.data_offset = (mmio.data_offset & 0xff00ffff) | (data << 16); + } + + if(addr == 0x2003) { + mmio.data_offset = (mmio.data_offset & 0x00ffffff) | (data << 24); + if(datafile.open()) datafile.seek(mmio.data_offset); + mmio.data_busy = false; + } + + if(addr == 0x2004) { + mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0); + } + + if(addr == 0x2005) { + mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8); + if(audiofile.open()) audiofile.close(); + if(audiofile.open(interface->path(Cartridge::Slot::Base, { "-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) { + uint32 header = audiofile.readm(4); + if(header != 0x4d535531) { //verify 'MSU1' header + audiofile.close(); + } else { + mmio.audio_offset = 8; + mmio.audio_loop_offset = 8 + audiofile.readl(4) * 4; + } + } + mmio.audio_busy = false; + mmio.audio_repeat = false; + mmio.audio_play = false; + } + + if(addr == 0x2006) { + mmio.audio_volume = data; + } + + if(addr == 0x2007) { + mmio.audio_repeat = data & 2; + mmio.audio_play = data & 1; + } +} + +} diff --git a/snes/chip/msu1/msu1.hpp b/snes/chip/msu1/msu1.hpp new file mode 100755 index 00000000..25572eaf --- /dev/null +++ b/snes/chip/msu1/msu1.hpp @@ -0,0 +1,43 @@ +class MSU1 : public Coprocessor { +public: + static void Enter(); + void enter(); + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + + void serialize(serializer&); + +private: + file datafile; + file audiofile; + + enum Flag { + DataBusy = 0x80, + AudioBusy = 0x40, + AudioRepeating = 0x20, + AudioPlaying = 0x10, + Revision = 0x01, + }; + + struct MMIO { + uint32 data_offset; + uint32 audio_offset; + uint32 audio_loop_offset; + + uint16 audio_track; + uint8 audio_volume; + + bool data_busy; + bool audio_busy; + bool audio_repeat; + bool audio_play; + } mmio; +}; + +extern MSU1 msu1; diff --git a/snes/chip/msu1/serialization.cpp b/snes/chip/msu1/serialization.cpp new file mode 100755 index 00000000..a5806b75 --- /dev/null +++ b/snes/chip/msu1/serialization.cpp @@ -0,0 +1,29 @@ +#ifdef MSU1_CPP + +void MSU1::serialize(serializer &s) { + Processor::serialize(s); + + s.integer(mmio.data_offset); + s.integer(mmio.audio_offset); + s.integer(mmio.audio_loop_offset); + + s.integer(mmio.audio_track); + s.integer(mmio.audio_volume); + + s.integer(mmio.data_busy); + s.integer(mmio.audio_busy); + s.integer(mmio.audio_repeat); + s.integer(mmio.audio_play); + + if(datafile.open()) datafile.close(); + if(datafile.open(interface->path(Cartridge::Slot::Base, ".msu"), file::mode::read)) { + datafile.seek(mmio.data_offset); + } + + if(audiofile.open()) audiofile.close(); + if(audiofile.open(interface->path(Cartridge::Slot::Base, { "-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) { + audiofile.seek(mmio.audio_offset); + } +} + +#endif diff --git a/snes/chip/necdsp/disassembler.cpp b/snes/chip/necdsp/disassembler.cpp new file mode 100755 index 00000000..23a5bb95 --- /dev/null +++ b/snes/chip/necdsp/disassembler.cpp @@ -0,0 +1,196 @@ +#ifdef NECDSP_CPP + +string NECDSP::disassemble(uint14 ip) { + string output = { hex<4>(ip), " " }; + uint24 opcode = programROM[ip]; + uint2 type = opcode >> 22; + + if(type == 0 || type == 1) { //OP,RT + uint2 pselect = opcode >> 20; + uint4 alu = opcode >> 16; + uint1 asl = opcode >> 15; + uint2 dpl = opcode >> 13; + uint4 dphm = opcode >> 9; + uint1 rpdcr = opcode >> 8; + uint4 src = opcode >> 4; + uint4 dst = opcode >> 0; + + switch(alu) { + case 0: output.append("nop "); break; + case 1: output.append("or "); break; + case 2: output.append("and "); break; + case 3: output.append("xor "); break; + case 4: output.append("sub "); break; + case 5: output.append("add "); break; + case 6: output.append("sbb "); break; + case 7: output.append("adc "); break; + case 8: output.append("dec "); break; + case 9: output.append("inc "); break; + case 10: output.append("cmp "); break; + case 11: output.append("shr1 "); break; + case 12: output.append("shl1 "); break; + case 13: output.append("shl2 "); break; + case 14: output.append("shl4 "); break; + case 15: output.append("xchg "); break; + } + + if(alu < 8) { + switch(pselect) { + case 0: output.append("ram,"); break; + case 1: output.append("idb,"); break; + case 2: output.append("m," ); break; + case 3: output.append("n," ); break; + } + } + + switch(asl) { + case 0: output.append("a"); break; + case 1: output.append("b"); break; + } + + output.append("\n mov "); + + switch(src) { + case 0: output.append("trb," ); break; + case 1: output.append("a," ); break; + case 2: output.append("b," ); break; + case 3: output.append("tr," ); break; + case 4: output.append("dp," ); break; + case 5: output.append("rp," ); break; + case 6: output.append("ro," ); break; + case 7: output.append("sgn," ); break; + case 8: output.append("dr," ); break; + case 9: output.append("drnf,"); break; + case 10: output.append("sr," ); break; + case 11: output.append("sim," ); break; + case 12: output.append("sil," ); break; + case 13: output.append("k," ); break; + case 14: output.append("l," ); break; + case 15: output.append("mem," ); break; + } + + switch(dst) { + case 0: output.append("non"); break; + case 1: output.append("a" ); break; + case 2: output.append("b" ); break; + case 3: output.append("tr" ); break; + case 4: output.append("dp" ); break; + case 5: output.append("rp" ); break; + case 6: output.append("dr" ); break; + case 7: output.append("sr" ); break; + case 8: output.append("sol"); break; + case 9: output.append("som"); break; + case 10: output.append("k" ); break; + case 11: output.append("klr"); break; + case 12: output.append("klm"); break; + case 13: output.append("l" ); break; + case 14: output.append("trb"); break; + case 15: output.append("mem"); break; + } + + if(dpl) { + switch(dpl) { + case 0: output.append("\n dpnop"); break; + case 1: output.append("\n dpinc"); break; + case 2: output.append("\n dpdec"); break; + case 3: output.append("\n dpclr"); break; + } + } + + if(dphm) { + output.append("\n m", hex<1>(dphm)); + } + + if(rpdcr == 1) { + output.append("\n rpdec"); + } + + if(type == 1) { + output.append("\n ret"); + } + } + + if(type == 2) { //JP + uint9 brch = opcode >> 13; + uint11 na = opcode >> 2; + uint8 bank = opcode >> 0; + + uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0); + + switch(brch) { + case 0x000: output.append("jmpso "); jp = 0; break; + case 0x080: output.append("jnca "); break; + case 0x082: output.append("jca "); break; + case 0x084: output.append("jncb "); break; + case 0x086: output.append("jcb "); break; + case 0x088: output.append("jnza "); break; + case 0x08a: output.append("jza "); break; + case 0x08c: output.append("jnzb "); break; + case 0x08e: output.append("jzb "); break; + case 0x090: output.append("jnova0 "); break; + case 0x092: output.append("jova0 "); break; + case 0x094: output.append("jnovb0 "); break; + case 0x096: output.append("jovb0 "); break; + case 0x098: output.append("jnova1 "); break; + case 0x09a: output.append("jova1 "); break; + case 0x09c: output.append("jnovb1 "); break; + case 0x09e: output.append("jovb1 "); break; + case 0x0a0: output.append("jnsa0 "); break; + case 0x0a2: output.append("jsa0 "); break; + case 0x0a4: output.append("jnsb0 "); break; + case 0x0a6: output.append("jsb0 "); break; + case 0x0a8: output.append("jnsa1 "); break; + case 0x0aa: output.append("jsa1 "); break; + case 0x0ac: output.append("jnsb1 "); break; + case 0x0ae: output.append("jsb1 "); break; + case 0x0b0: output.append("jdpl0 "); break; + case 0x0b1: output.append("jdpln0 "); break; + case 0x0b2: output.append("jdplf "); break; + case 0x0b3: output.append("jdplnf "); break; + case 0x0b4: output.append("jnsiak "); break; + case 0x0b6: output.append("jsiak "); break; + case 0x0b8: output.append("jnsoak "); break; + case 0x0ba: output.append("jsoak "); break; + case 0x0bc: output.append("jnrqm "); break; + case 0x0be: output.append("jrqm "); break; + case 0x100: output.append("ljmp "); jp &= ~0x2000; break; + case 0x101: output.append("hjmp "); jp |= 0x2000; break; + case 0x140: output.append("lcall "); jp &= ~0x2000; break; + case 0x141: output.append("hcall "); jp |= 0x2000; break; + default: output.append("?????? "); break; + } + + output.append("$", hex<4>(jp)); + } + + if(type == 3) { //LD + output.append("ld "); + uint16 id = opcode >> 6; + uint4 dst = opcode >> 0; + + output.append("$", hex<4>(id), ","); + + switch(dst) { + case 0: output.append("non"); break; + case 1: output.append("a" ); break; + case 2: output.append("b" ); break; + case 3: output.append("tr" ); break; + case 4: output.append("dp" ); break; + case 5: output.append("rp" ); break; + case 6: output.append("dr" ); break; + case 7: output.append("sr" ); break; + case 8: output.append("sol"); break; + case 9: output.append("som"); break; + case 10: output.append("k" ); break; + case 11: output.append("klr"); break; + case 12: output.append("klm"); break; + case 13: output.append("l" ); break; + case 14: output.append("trb"); break; + case 15: output.append("mem"); break; + } + } + + return output; +} + +#endif diff --git a/snes/chip/necdsp/memory.cpp b/snes/chip/necdsp/memory.cpp new file mode 100755 index 00000000..0b11d594 --- /dev/null +++ b/snes/chip/necdsp/memory.cpp @@ -0,0 +1,74 @@ +#ifdef NECDSP_CPP + +uint8 NECDSP::sr_read(unsigned) { + cpu.synchronize_coprocessors(); + return regs.sr >> 8; +} + +void NECDSP::sr_write(unsigned, uint8 data) { + cpu.synchronize_coprocessors(); +} + +uint8 NECDSP::dr_read(unsigned) { + cpu.synchronize_coprocessors(); + if(regs.sr.drc == 0) { + //16-bit + if(regs.sr.drs == 0) { + regs.sr.drs = 1; + return regs.dr >> 0; + } else { + regs.sr.rqm = 0; + regs.sr.drs = 0; + return regs.dr >> 8; + } + } else { + //8-bit + regs.sr.rqm = 0; + return regs.dr >> 0; + } +} + +void NECDSP::dr_write(unsigned, uint8 data) { + cpu.synchronize_coprocessors(); + if(regs.sr.drc == 0) { + //16-bit + if(regs.sr.drs == 0) { + regs.sr.drs = 1; + regs.dr = (regs.dr & 0xff00) | (data << 0); + } else { + regs.sr.rqm = 0; + regs.sr.drs = 0; + regs.dr = (data << 8) | (regs.dr & 0x00ff); + } + } else { + //8-bit + regs.sr.rqm = 0; + regs.dr = (regs.dr & 0xff00) | (data << 0); + } +} + +uint8 NECDSP::dp_read(unsigned addr) { + cpu.synchronize_coprocessors(); + bool hi = addr & 1; + addr = (addr >> 1) & 2047; + + if(hi == false) { + return dataRAM[addr] >> 0; + } else { + return dataRAM[addr] >> 8; + } +} + +void NECDSP::dp_write(unsigned addr, uint8 data) { + cpu.synchronize_coprocessors(); + bool hi = addr & 1; + addr = (addr >> 1) & 2047; + + if(hi == false) { + dataRAM[addr] = (dataRAM[addr] & 0xff00) | (data << 0); + } else { + dataRAM[addr] = (dataRAM[addr] & 0x00ff) | (data << 8); + } +} + +#endif diff --git a/snes/chip/necdsp/necdsp.cpp b/snes/chip/necdsp/necdsp.cpp new file mode 100755 index 00000000..0a07d1dc --- /dev/null +++ b/snes/chip/necdsp/necdsp.cpp @@ -0,0 +1,303 @@ +#include + +#define NECDSP_CPP +namespace SNES { + +#include "memory.cpp" +#include "disassembler.cpp" +#include "serialization.cpp" +NECDSP necdsp; + +void NECDSP::Enter() { necdsp.enter(); } + +void NECDSP::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + uint24 opcode = programROM[regs.pc++]; + switch(opcode >> 22) { + case 0: exec_op(opcode); break; + case 1: exec_rt(opcode); break; + case 2: exec_jp(opcode); break; + case 3: exec_ld(opcode); break; + } + + int32 result = (int32)regs.k * regs.l; //sign + 30-bit result + regs.m = result >> 15; //store sign + top 15-bits + regs.n = result << 1; //store low 15-bits + zero + + step(1); + synchronize_cpu(); + } +} + +void NECDSP::exec_op(uint24 opcode) { + uint2 pselect = opcode >> 20; //P select + uint4 alu = opcode >> 16; //ALU operation mode + uint1 asl = opcode >> 15; //accumulator select + uint2 dpl = opcode >> 13; //DP low modify + uint4 dphm = opcode >> 9; //DP high XOR modify + uint1 rpdcr = opcode >> 8; //RP decrement + uint4 src = opcode >> 4; //move source + uint4 dst = opcode >> 0; //move destination + + uint16 idb; + switch(src) { + case 0: idb = regs.trb; break; + case 1: idb = regs.a; break; + case 2: idb = regs.b; break; + case 3: idb = regs.tr; break; + case 4: idb = regs.dp; break; + case 5: idb = regs.rp; break; + case 6: idb = dataROM[regs.rp]; break; + case 7: idb = 0x8000 - regs.flaga.s1; break; + case 8: idb = regs.dr; regs.sr.rqm = 1; break; + case 9: idb = regs.dr; break; + case 10: idb = regs.sr; break; + case 11: idb = regs.si; break; //MSB + case 12: idb = regs.si; break; //LSB + case 13: idb = regs.k; break; + case 14: idb = regs.l; break; + case 15: idb = dataRAM[regs.dp]; break; + } + + if(alu) { + uint16 p, q, r; + Flag flag; + bool c; + + switch(pselect) { + case 0: p = dataRAM[regs.dp]; break; + case 1: p = idb; break; + case 2: p = regs.m; break; + case 3: p = regs.n; break; + } + + switch(asl) { + case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break; + case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break; + } + + switch(alu) { + case 1: r = q | p; break; //OR + case 2: r = q & p; break; //AND + case 3: r = q ^ p; break; //XOR + case 4: r = q - p; break; //SUB + case 5: r = q + p; break; //ADD + case 6: r = q - p - c; break; //SBB + case 7: r = q + p + c; break; //ADC + case 8: r = q - 1; p = 1; break; //DEC + case 9: r = q + 1; p = 1; break; //INC + case 10: r = ~q; break; //CMP + case 11: r = (q >> 1) | (q & 0x8000); break; //SHR1 (ASR) + case 12: r = (q << 1) | c; break; //SHL1 (ROL) + case 13: r = (q << 2) | 3; break; //SHL2 + case 14: r = (q << 4) | 15; break; //SHL4 + case 15: r = (q << 8) | (q >> 8); break; //XCHG + } + + flag.s0 = (r & 0x8000); + flag.z = (r == 0); + + switch(alu) { + case 1: case 2: case 3: case 10: case 13: case 14: case 15: { + flag.c = 0; + flag.ov0 = 0; + flag.ov1 = 0; + break; + } + case 4: case 5: case 6: case 7: case 8: case 9: { + if(alu & 1) { + //addition + flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000; + flag.c = (r < q); + } else { + //subtraction + flag.ov0 = (q ^ r) & (q ^ p) & 0x8000; + flag.c = (r > q); + } + if(flag.ov0) { + flag.s1 = flag.ov1 ^ !(r & 0x8000); + flag.ov1 = !flag.ov1; + } + break; + } + case 11: { + flag.c = q & 1; + flag.ov0 = 0; + flag.ov1 = 0; + break; + } + case 12: { + flag.c = q >> 15; + flag.ov0 = 0; + flag.ov1 = 0; + break; + } + } + + switch(asl) { + case 0: regs.a = r; regs.flaga = flag; break; + case 1: regs.b = r; regs.flagb = flag; break; + } + } + + exec_ld((idb << 6) + dst); + + switch(dpl) { + case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC + case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC + case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR + } + + regs.dp ^= dphm << 4; + + if(rpdcr) regs.rp--; +} + +void NECDSP::exec_rt(uint24 opcode) { + exec_op(opcode); + regs.pc = regs.stack[--regs.sp]; +} + +void NECDSP::exec_jp(uint24 opcode) { + uint9 brch = opcode >> 13; //branch + uint11 na = opcode >> 2; //next address + uint2 bank = opcode >> 0; //bank address + + uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0); + + switch(brch) { + case 0x000: regs.pc = regs.so; return; //JMPSO + + case 0x080: if(regs.flaga.c == 0) regs.pc = jp; return; //JNCA + case 0x082: if(regs.flaga.c == 1) regs.pc = jp; return; //JCA + case 0x084: if(regs.flagb.c == 0) regs.pc = jp; return; //JNCB + case 0x086: if(regs.flagb.c == 1) regs.pc = jp; return; //JCB + + case 0x088: if(regs.flaga.z == 0) regs.pc = jp; return; //JNZA + case 0x08a: if(regs.flaga.z == 1) regs.pc = jp; return; //JZA + case 0x08c: if(regs.flagb.z == 0) regs.pc = jp; return; //JNZB + case 0x08e: if(regs.flagb.z == 1) regs.pc = jp; return; //JZB + + case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jp; return; //JNOVA0 + case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jp; return; //JOVA0 + case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jp; return; //JNOVB0 + case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jp; return; //JOVB0 + + case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jp; return; //JNOVA1 + case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jp; return; //JOVA1 + case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jp; return; //JNOVB1 + case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jp; return; //JOVB1 + + case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jp; return; //JNSA0 + case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jp; return; //JSA0 + case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jp; return; //JNSB0 + case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jp; return; //JSB0 + + case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jp; return; //JNSA1 + case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jp; return; //JSA1 + case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jp; return; //JNSB1 + case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jp; return; //JSB1 + + case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jp; return; //JDPL0 + case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jp; return; //JDPLN0 + case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jp; return; //JDPLF + case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jp; return; //JDPLNF + + case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jp; return; //JNRQM + case 0x0be: if(regs.sr.rqm == 1) regs.pc = jp; return; //JRQM + + case 0x100: regs.pc = jp & ~0x2000; return; //LJMP + case 0x101: regs.pc = jp | 0x2000; return; //HJMP + + case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = jp & ~0x2000; return; //LCALL + case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = jp | 0x2000; return; //HCALL + } +} + +void NECDSP::exec_ld(uint24 opcode) { + uint16 id = opcode >> 6; //immediate data + uint4 dst = opcode >> 0; //destination + + switch(dst) { + case 0: break; + case 1: regs.a = id; break; + case 2: regs.b = id; break; + case 3: regs.tr = id; break; + case 4: regs.dp = id; break; + case 5: regs.rp = id; break; + case 6: regs.dr = id; regs.sr.rqm = 1; break; + case 7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c); break; + case 8: regs.so = id; break; //LSB + case 9: regs.so = id; break; //MSB + case 10: regs.k = id; break; + case 11: regs.k = id; regs.l = dataROM[regs.rp]; break; + case 12: regs.l = id; regs.k = dataRAM[regs.dp | 0x40]; break; + case 13: regs.l = id; break; + case 14: regs.trb = id; break; + case 15: dataRAM[regs.dp] = id; break; + } +} + +void NECDSP::init() { +} + +void NECDSP::load() { + if(revision == Revision::uPD96050) { + cartridge.nvram.append({ ".nec", (uint8_t*)dataRAM, 4096 }); + } +} + +void NECDSP::unload() { +} + +void NECDSP::power() { + if(revision == Revision::uPD7725) { + regs.pc.bits(11); + regs.rp.bits(10); + regs.dp.bits( 8); + } + + if(revision == Revision::uPD96050) { + regs.pc.bits(14); + regs.rp.bits(11); + regs.dp.bits(11); + } + + reset(); +} + +void NECDSP::reset() { + create(NECDSP::Enter, frequency); + + for(unsigned n = 0; n < 16; n++) regs.stack[n] = 0x0000; + regs.pc = 0x0000; + regs.rp = 0x0000; + regs.dp = 0x0000; + regs.sp = 0x0; + regs.k = 0x0000; + regs.l = 0x0000; + regs.m = 0x0000; + regs.n = 0x0000; + regs.a = 0x0000; + regs.b = 0x0000; + regs.flaga = 0x00; + regs.flagb = 0x00; + regs.tr = 0x0000; + regs.trb = 0x0000; + regs.sr = 0x0000; + regs.dr = 0x0000; + regs.si = 0x0000; + regs.so = 0x0000; +} + +NECDSP::NECDSP() { +} + +NECDSP::~NECDSP() { +} + +} diff --git a/snes/chip/necdsp/necdsp.hpp b/snes/chip/necdsp/necdsp.hpp new file mode 100755 index 00000000..3c041cf7 --- /dev/null +++ b/snes/chip/necdsp/necdsp.hpp @@ -0,0 +1,49 @@ +//NEC uPD7725 +//NEC uPD96050 + +class NECDSP : public Coprocessor { +public: + enum class Revision : unsigned { uPD7725, uPD96050 } revision; + unsigned frequency; + + #include "registers.hpp" + + uint24 programROM[16384]; + uint16 dataROM[2048]; + uint16 dataRAM[2048]; + + unsigned programROMSize; + unsigned dataROMSize; + unsigned dataRAMSize; + + static void Enter(); + void enter(); + + void exec_op(uint24 opcode); + void exec_rt(uint24 opcode); + void exec_jp(uint24 opcode); + void exec_ld(uint24 opcode); + + string disassemble(uint14 ip); + + uint8 sr_read(unsigned); + void sr_write(unsigned, uint8 data); + + uint8 dr_read(unsigned); + void dr_write(unsigned, uint8 data); + + uint8 dp_read(unsigned addr); + void dp_write(unsigned addr, uint8 data); + + void init(); + void load(); + void unload(); + void power(); + void reset(); + + void serialize(serializer&); + NECDSP(); + ~NECDSP(); +}; + +extern NECDSP necdsp; diff --git a/snes/chip/necdsp/registers.hpp b/snes/chip/necdsp/registers.hpp new file mode 100755 index 00000000..ff5de61f --- /dev/null +++ b/snes/chip/necdsp/registers.hpp @@ -0,0 +1,51 @@ +struct Flag { + bool s1, s0, c, z, ov1, ov0; + + inline operator unsigned() const { + return (s1 << 5) + (s0 << 4) + (c << 3) + (z << 2) + (ov1 << 1) + (ov0 << 0); + } + + inline unsigned operator=(unsigned d) { + s1 = d & 0x20; s0 = d & 0x10; c = d & 0x08; z = d & 0x04; ov1 = d & 0x02; ov0 = d & 0x01; + return d; + } +}; + +struct Status { + bool rqm, usf1, usf0, drs, dma, drc, soc, sic, ei, p1, p0; + + inline operator unsigned() const { + return (rqm << 15) + (usf1 << 14) + (usf0 << 13) + (drs << 12) + + (dma << 11) + (drc << 10) + (soc << 9) + (sic << 8) + + (ei << 7) + (p1 << 1) + (p0 << 0); + } + + inline unsigned operator=(unsigned d) { + rqm = d & 0x8000; usf1 = d & 0x4000; usf0 = d & 0x2000; drs = d & 0x1000; + dma = d & 0x0800; drc = d & 0x0400; soc = d & 0x0200; sic = d & 0x0100; + ei = d & 0x0080; p1 = d & 0x0002; p0 = d & 0x0001; + return d; + } +}; + +struct Regs { + uint16 stack[16]; //LIFO + varuint pc; //program counter + varuint rp; //ROM pointer + varuint dp; //data pointer + uint4 sp; //stack pointer + int16 k; + int16 l; + int16 m; + int16 n; + int16 a; //accumulator + int16 b; //accumulator + Flag flaga; + Flag flagb; + uint16 tr; //temporary register + uint16 trb; //temporary register + Status sr; //status register + uint16 dr; //data register + uint16 si; + uint16 so; +} regs; diff --git a/snes/chip/necdsp/serialization.cpp b/snes/chip/necdsp/serialization.cpp new file mode 100755 index 00000000..a06510f8 --- /dev/null +++ b/snes/chip/necdsp/serialization.cpp @@ -0,0 +1,55 @@ +#ifdef NECDSP_CPP + +void NECDSP::serialize(serializer &s) { + Processor::serialize(s); + + s.array(dataRAM); + + s.array(regs.stack); + s.integer(regs.pc); + s.integer(regs.rp); + s.integer(regs.dp); + s.integer(regs.sp); + + s.integer(regs.k); + s.integer(regs.l); + s.integer(regs.m); + s.integer(regs.n); + s.integer(regs.a); + s.integer(regs.b); + + s.integer(regs.flaga.s1); + s.integer(regs.flaga.s0); + s.integer(regs.flaga.c); + s.integer(regs.flaga.z); + s.integer(regs.flaga.ov1); + s.integer(regs.flaga.ov0); + + s.integer(regs.flagb.s1); + s.integer(regs.flagb.s0); + s.integer(regs.flagb.c); + s.integer(regs.flagb.z); + s.integer(regs.flagb.ov1); + s.integer(regs.flagb.ov0); + + s.integer(regs.tr); + s.integer(regs.trb); + + s.integer(regs.sr.rqm); + s.integer(regs.sr.usf1); + s.integer(regs.sr.usf0); + s.integer(regs.sr.drs); + s.integer(regs.sr.dma); + s.integer(regs.sr.drc); + s.integer(regs.sr.soc); + s.integer(regs.sr.sic); + s.integer(regs.sr.ei); + s.integer(regs.sr.p1); + s.integer(regs.sr.p0); + + s.integer(regs.dr); + s.integer(regs.si); + s.integer(regs.so); +} + +#endif diff --git a/snes/chip/nss/nss.cpp b/snes/chip/nss/nss.cpp new file mode 100755 index 00000000..964973d0 --- /dev/null +++ b/snes/chip/nss/nss.cpp @@ -0,0 +1,39 @@ +#include + +#define NSS_CPP +namespace SNES { + +NSS nss; + +void NSS::init() { +} + +void NSS::load() { + dip = 0x0000; + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4100, 0x4101, { &NSS::read, this }, { &NSS::write, this }); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4100, 0x4101, { &NSS::read, this }, { &NSS::write, this }); +} + +void NSS::unload() { +} + +void NSS::power() { +} + +void NSS::reset() { +} + +void NSS::set_dip(uint16 dip) { + this->dip = dip; +} + +uint8 NSS::read(unsigned addr) { + if((addr & 0x40ffff) == 0x004100) return dip >> 0; + if((addr & 0x40ffff) == 0x004101) return dip >> 8; + return cpu.regs.mdr; +} + +void NSS::write(unsigned addr, uint8 data) { +} + +} diff --git a/snes/chip/nss/nss.hpp b/snes/chip/nss/nss.hpp new file mode 100755 index 00000000..3cab46da --- /dev/null +++ b/snes/chip/nss/nss.hpp @@ -0,0 +1,17 @@ +class NSS { +public: + void init(); + void load(); + void unload(); + void power(); + void reset(); + + void set_dip(uint16 dip); + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); + +private: + uint16 dip; +}; + +extern NSS nss; diff --git a/snes/chip/obc1/obc1.cpp b/snes/chip/obc1/obc1.cpp new file mode 100755 index 00000000..6cfc11f3 --- /dev/null +++ b/snes/chip/obc1/obc1.cpp @@ -0,0 +1,80 @@ +#include + +#define OBC1_CPP +namespace SNES { + +#include "serialization.cpp" +OBC1 obc1; + +void OBC1::init() { +} + +void OBC1::load() { +} + +void OBC1::unload() { +} + +void OBC1::power() { + reset(); +} + +void OBC1::reset() { + status.baseptr = (ram_read(0x1ff5) & 1) ? 0x1800 : 0x1c00; + status.address = (ram_read(0x1ff6) & 0x7f); + status.shift = (ram_read(0x1ff6) & 3) << 1; +} + +uint8 OBC1::read(unsigned addr) { + addr &= 0x1fff; + + switch(addr) { + case 0x1ff0: return ram_read(status.baseptr + (status.address << 2) + 0); + case 0x1ff1: return ram_read(status.baseptr + (status.address << 2) + 1); + case 0x1ff2: return ram_read(status.baseptr + (status.address << 2) + 2); + case 0x1ff3: return ram_read(status.baseptr + (status.address << 2) + 3); + case 0x1ff4: return ram_read(status.baseptr + (status.address >> 2) + 0x200); + } + + return ram_read(addr); +} + +void OBC1::write(unsigned addr, uint8 data) { + addr &= 0x1fff; + + switch(addr) { + case 0x1ff0: ram_write(status.baseptr + (status.address << 2) + 0, data); return; + case 0x1ff1: ram_write(status.baseptr + (status.address << 2) + 1, data); return; + case 0x1ff2: ram_write(status.baseptr + (status.address << 2) + 2, data); return; + case 0x1ff3: ram_write(status.baseptr + (status.address << 2) + 3, data); return; + case 0x1ff4: { + uint8 temp = ram_read(status.baseptr + (status.address >> 2) + 0x200); + temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift); + ram_write(status.baseptr + (status.address >> 2) + 0x200, temp); + } return; + case 0x1ff5: + status.baseptr = (data & 1) ? 0x1800 : 0x1c00; + ram_write(addr, data); + return; + case 0x1ff6: + status.address = (data & 0x7f); + status.shift = (data & 3) << 1; + ram_write(addr, data); + return; + case 0x1ff7: + ram_write(addr, data); + return; + } + + return ram_write(addr, data); +} + +uint8 OBC1::ram_read(unsigned addr) { + return cartridge.ram.read(addr & 0x1fff); +} + +void OBC1::ram_write(unsigned addr, uint8 data) { + cartridge.ram.write(addr & 0x1fff, data); +} + +} diff --git a/snes/chip/obc1/obc1.hpp b/snes/chip/obc1/obc1.hpp new file mode 100755 index 00000000..686adbc9 --- /dev/null +++ b/snes/chip/obc1/obc1.hpp @@ -0,0 +1,25 @@ +class OBC1 { +public: + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); + + void serialize(serializer&); + +private: + uint8 ram_read(unsigned addr); + void ram_write(unsigned addr, uint8 data); + + struct { + uint16 address; + uint16 baseptr; + uint16 shift; + } status; +}; + +extern OBC1 obc1; diff --git a/snes/chip/obc1/serialization.cpp b/snes/chip/obc1/serialization.cpp new file mode 100755 index 00000000..3d61aafc --- /dev/null +++ b/snes/chip/obc1/serialization.cpp @@ -0,0 +1,9 @@ +#ifdef OBC1_CPP + +void OBC1::serialize(serializer &s) { + s.integer(status.address); + s.integer(status.baseptr); + s.integer(status.shift); +} + +#endif diff --git a/snes/chip/sa1/bus/bus.cpp b/snes/chip/sa1/bus/bus.cpp new file mode 100755 index 00000000..a632551a --- /dev/null +++ b/snes/chip/sa1/bus/bus.cpp @@ -0,0 +1,34 @@ +#ifdef SA1_CPP + +//ROM / RAM access from the S-CPU + +unsigned SA1::CPUIRAM::size() const { + return sa1.iram.size(); +} + +uint8 SA1::CPUIRAM::read(unsigned addr) { + cpu.synchronize_coprocessors(); + return sa1.iram.read(addr); +} + +void SA1::CPUIRAM::write(unsigned addr, uint8 data) { + cpu.synchronize_coprocessors(); + sa1.iram.write(addr, data); +} + +unsigned SA1::CPUBWRAM::size() const { + return cartridge.ram.size(); +} + +uint8 SA1::CPUBWRAM::read(unsigned addr) { + 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_coprocessors(); + cartridge.ram.write(addr, data); +} + +#endif diff --git a/snes/chip/sa1/bus/bus.hpp b/snes/chip/sa1/bus/bus.hpp new file mode 100755 index 00000000..e3b42b97 --- /dev/null +++ b/snes/chip/sa1/bus/bus.hpp @@ -0,0 +1,14 @@ +StaticRAM iram; + +struct CPUIRAM : Memory { + unsigned size() const; + alwaysinline uint8 read(unsigned); + alwaysinline void write(unsigned, uint8); +} cpuiram; + +struct CPUBWRAM : Memory { + unsigned size() const; + alwaysinline uint8 read(unsigned); + alwaysinline void write(unsigned, uint8); + bool dma; +} cpubwram; diff --git a/snes/chip/sa1/dma/dma.cpp b/snes/chip/sa1/dma/dma.cpp new file mode 100755 index 00000000..71148865 --- /dev/null +++ b/snes/chip/sa1/dma/dma.cpp @@ -0,0 +1,139 @@ +#ifdef SA1_CPP + +//==================== +//direct data transfer +//==================== + +void SA1::dma_normal() { + while(mmio.dtc--) { + uint8 data = regs.mdr; + uint32 dsa = mmio.dsa++; + uint32 dda = mmio.dda++; + + //source and destination cannot be the same + if(mmio.sd == DMA::SourceBWRAM && mmio.dd == DMA::DestBWRAM) continue; + if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestIRAM ) continue; + + switch(mmio.sd) { + case DMA::SourceROM: { + if((dsa & 0x408000) == 0x008000 || (dsa & 0xc00000) == 0xc00000) { + data = bus_read(dsa); + } + } break; + + case DMA::SourceBWRAM: { + if((dsa & 0x40e000) == 0x006000 || (dsa & 0xf00000) == 0x400000) { + data = bus_read(dsa); + } + } break; + + case DMA::SourceIRAM: { + data = iram.read(dsa & 0x07ff); + } break; + } + + switch(mmio.dd) { + case DMA::DestBWRAM: { + if((dda & 0x40e000) == 0x006000 || (dda & 0xf00000) == 0x400000) { + bus_write(dda, data); + } + } break; + + case DMA::DestIRAM: { + iram.write(dda & 0x07ff, data); + } break; + } + } + + mmio.dma_irqfl = true; + if(mmio.dma_irqen) mmio.dma_irqcl = 0; +} + +//((byte & 6) << 3) + (byte & 1) explanation: +//transforms a byte index (0-7) into a planar index: +//result[] = { 0, 1, 16, 17, 32, 33, 48, 49 }; +//works for 2bpp, 4bpp and 8bpp modes + +//=========================== +//type-1 character conversion +//=========================== + +void SA1::dma_cc1() { + cpubwram.dma = true; + mmio.chdma_irqfl = true; + if(mmio.chdma_irqen) { + mmio.chdma_irqcl = 0; + cpu.regs.irq = 1; + } +} + +uint8 SA1::dma_cc1_read(unsigned addr) { + //16 bytes/char (2bpp); 32 bytes/char (4bpp); 64 bytes/char (8bpp) + unsigned charmask = (1 << (6 - mmio.dmacb)) - 1; + + if((addr & charmask) == 0) { + //buffer next character to I-RAM + unsigned bpp = 2 << (2 - mmio.dmacb); + unsigned bpl = (8 << mmio.dmasize) >> mmio.dmacb; + unsigned bwmask = cartridge.ram.size() - 1; + unsigned tile = ((addr - mmio.dsa) & bwmask) >> (6 - mmio.dmacb); + unsigned ty = (tile >> mmio.dmasize); + unsigned tx = tile & ((1 << mmio.dmasize) - 1); + unsigned bwaddr = mmio.dsa + ty * 8 * bpl + tx * bpp; + + for(unsigned y = 0; y < 8; y++) { + uint64 data = 0; + for(unsigned byte = 0; byte < bpp; byte++) { + data |= (uint64)cartridge.ram.read((bwaddr + byte) & bwmask) << (byte << 3); + } + bwaddr += bpl; + + uint8 out[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + for(unsigned x = 0; x < 8; x++) { + out[0] |= (data & 1) << (7 - x); data >>= 1; + out[1] |= (data & 1) << (7 - x); data >>= 1; + if(mmio.dmacb == 2) continue; + out[2] |= (data & 1) << (7 - x); data >>= 1; + out[3] |= (data & 1) << (7 - x); data >>= 1; + if(mmio.dmacb == 1) continue; + out[4] |= (data & 1) << (7 - x); data >>= 1; + out[5] |= (data & 1) << (7 - x); data >>= 1; + out[6] |= (data & 1) << (7 - x); data >>= 1; + out[7] |= (data & 1) << (7 - x); data >>= 1; + } + + for(unsigned byte = 0; byte < bpp; byte++) { + unsigned p = mmio.dda + (y << 1) + ((byte & 6) << 3) + (byte & 1); + iram.write(p & 0x07ff, out[byte]); + } + } + } + + return iram.read((mmio.dda + (addr & charmask)) & 0x07ff); +} + +//=========================== +//type-2 character conversion +//=========================== + +void SA1::dma_cc2() { + //select register file index (0-7 or 8-15) + const uint8 *brf = &mmio.brf[(dma.line & 1) << 3]; + unsigned bpp = 2 << (2 - mmio.dmacb); + unsigned addr = mmio.dda & 0x07ff; + addr &= ~((1 << (7 - mmio.dmacb)) - 1); + addr += (dma.line & 8) * bpp; + addr += (dma.line & 7) * 2; + + for(unsigned byte = 0; byte < bpp; byte++) { + uint8 output = 0; + for(unsigned bit = 0; bit < 8; bit++) { + output |= ((brf[bit] >> byte) & 1) << (7 - bit); + } + iram.write(addr + ((byte & 6) << 3) + (byte & 1), output); + } + + dma.line = (dma.line + 1) & 15; +} + +#endif diff --git a/snes/chip/sa1/dma/dma.hpp b/snes/chip/sa1/dma/dma.hpp new file mode 100755 index 00000000..4d3cff7f --- /dev/null +++ b/snes/chip/sa1/dma/dma.hpp @@ -0,0 +1,11 @@ +struct DMA { + enum CDEN { DmaNormal = 0, DmaCharConversion = 1 }; + enum SD { SourceROM = 0, SourceBWRAM = 1, SourceIRAM = 2 }; + enum DD { DestIRAM = 0, DestBWRAM = 1 }; + unsigned line; +} dma; + +void dma_normal(); +void dma_cc1(); +uint8 dma_cc1_read(unsigned addr); +void dma_cc2(); diff --git a/snes/chip/sa1/memory/memory.cpp b/snes/chip/sa1/memory/memory.cpp new file mode 100755 index 00000000..d13ac929 --- /dev/null +++ b/snes/chip/sa1/memory/memory.cpp @@ -0,0 +1,264 @@ +#ifdef SA1_CPP + +uint8 SA1::bus_read(unsigned addr) { + if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff + return mmio_read(addr); + } + + if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff + return mmc_read(addr); + } + + if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff + return mmc_read(addr); + } + + if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff + return mmc_sa1_read(addr); + } + + if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff + synchronize_cpu(); + return iram.read(addr & 2047); + } + + if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff + synchronize_cpu(); + return iram.read(addr & 2047); + } + + if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff + synchronize_cpu(); + return cartridge.ram.read(addr & (cartridge.ram.size() - 1)); + } + + if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff + synchronize_cpu(); + return bitmap_read(addr & 0x0fffff); + } +} + +void SA1::bus_write(unsigned addr, uint8 data) { + if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff + return mmio_write(addr, data); + } + + if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff + return mmc_sa1_write(addr, data); + } + + if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff + synchronize_cpu(); + return iram.write(addr & 2047, data); + } + + if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff + synchronize_cpu(); + return iram.write(addr & 2047, data); + } + + if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff + synchronize_cpu(); + return cartridge.ram.write(addr & (cartridge.ram.size() - 1), data); + } + + if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff + synchronize_cpu(); + return bitmap_write(addr & 0x0fffff, data); + } +} + +//$230c (VDPL), $230d (VDPH) use this bus to read variable-length data. +//this is used both to keep VBR-reads from accessing MMIO registers, and +//to avoid syncing the S-CPU and SA-1*; as both chips are able to access +//these ports. +uint8 SA1::vbr_read(unsigned addr) { + if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff + return mmc_read(addr); + } + + if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff + return mmc_read(addr); + } + + if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff + return cartridge.ram.read(addr & (cartridge.ram.size() - 1)); + } + + if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff + return cartridge.ram.read(addr & (cartridge.ram.size() - 1)); + } + + if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff + return iram.read(addr & 2047); + } + + if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff + return iram.read(addr & 0x2047); + } +} + +//ROM, I-RAM and MMIO registers are accessed at ~10.74MHz (2 clock ticks) +//BW-RAM is accessed at ~5.37MHz (4 clock ticks) +//tick() == 2 clock ticks +//note: bus conflict delays are not emulated at this time + +void SA1::op_io() { + tick(); +} + +uint8 SA1::op_read(unsigned addr) { + tick(); + if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick(); + return bus_read(addr); +} + +void SA1::op_write(unsigned addr, uint8 data) { + tick(); + if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick(); + bus_write(addr, data); +} + +uint8 SA1::mmc_read(unsigned addr) { + if((addr & 0xffffe0) == 0x00ffe0) { + if(addr == 0xffea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0; + if(addr == 0xffeb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8; + if(addr == 0xffee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0; + if(addr == 0xffef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8; + } + + static auto read = [](unsigned addr) { + return cartridge.rom.read(bus.mirror(addr, cartridge.rom.size())); + }; + + if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff + addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff); + if(mmio.cbmode == 0) return read(0x000000 | addr); + return read((mmio.cb << 20) | addr); + } + + if((addr & 0xe08000) == 0x208000) { //$20-3f:8000-ffff + addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff); + if(mmio.dbmode == 0) return read(0x100000 | addr); + return read((mmio.db << 20) | addr); + } + + if((addr & 0xe08000) == 0x808000) { //$80-9f:8000-ffff + addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff); + if(mmio.ebmode == 0) return read(0x200000 | addr); + return read((mmio.eb << 20) | addr); + } + + if((addr & 0xe08000) == 0xa08000) { //$a0-bf:8000-ffff + addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff); + if(mmio.fbmode == 0) return read(0x300000 | addr); + return read((mmio.fb << 20) | addr); + } + + if((addr & 0xf00000) == 0xc00000) { //$c0-cf:0000-ffff + return read((mmio.cb << 20) | (addr & 0x0fffff)); + } + + if((addr & 0xf00000) == 0xd00000) { //$d0-df:0000-ffff + return read((mmio.db << 20) | (addr & 0x0fffff)); + } + + if((addr & 0xf00000) == 0xe00000) { //$e0-ef:0000-ffff + return read((mmio.eb << 20) | (addr & 0x0fffff)); + } + + if((addr & 0xf00000) == 0xf00000) { //$f0-ff:0000-ffff + return read((mmio.fb << 20) | (addr & 0x0fffff)); + } + + return 0x00; +} + +void SA1::mmc_write(unsigned addr, uint8 data) { +} + +uint8 SA1::mmc_cpu_read(unsigned addr) { + 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_coprocessors(); + addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size()); + cpubwram.write(addr, data); +} + +uint8 SA1::mmc_sa1_read(unsigned addr) { + synchronize_cpu(); + if(mmio.sw46 == 0) { + //$40-43:0000-ffff x 32 projection + addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), cartridge.ram.size()); + return cartridge.ram.read(addr); + } else { + //$60-6f:0000-ffff x 128 projection + addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000); + return bitmap_read(addr); + } +} + +void SA1::mmc_sa1_write(unsigned addr, uint8 data) { + synchronize_cpu(); + if(mmio.sw46 == 0) { + //$40-43:0000-ffff x 32 projection + addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), cartridge.ram.size()); + cartridge.ram.write(addr, data); + } else { + //$60-6f:0000-ffff x 128 projection + addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000); + bitmap_write(addr, data); + } +} + +uint8 SA1::bitmap_read(unsigned addr) { + if(mmio.bbf == 0) { + //4bpp + unsigned shift = addr & 1; + addr = (addr >> 1) & (cartridge.ram.size() - 1); + switch(shift) { default: + case 0: return (cartridge.ram.read(addr) >> 0) & 15; + case 1: return (cartridge.ram.read(addr) >> 4) & 15; + } + } else { + //2bpp + unsigned shift = addr & 3; + addr = (addr >> 2) & (cartridge.ram.size() - 1); + switch(shift) { default: + case 0: return (cartridge.ram.read(addr) >> 0) & 3; + case 1: return (cartridge.ram.read(addr) >> 2) & 3; + case 2: return (cartridge.ram.read(addr) >> 4) & 3; + case 3: return (cartridge.ram.read(addr) >> 6) & 3; + } + } +} + +void SA1::bitmap_write(unsigned addr, uint8 data) { + if(mmio.bbf == 0) { + //4bpp + unsigned shift = addr & 1; + addr = (addr >> 1) & (cartridge.ram.size() - 1); + switch(shift) { default: + case 0: data = (cartridge.ram.read(addr) & 0xf0) | ((data & 15) << 0); break; + case 1: data = (cartridge.ram.read(addr) & 0x0f) | ((data & 15) << 4); break; + } + } else { + //2bpp + unsigned shift = addr & 3; + addr = (addr >> 2) & (cartridge.ram.size() - 1); + switch(shift) { default: + case 0: data = (cartridge.ram.read(addr) & 0xfc) | ((data & 3) << 0); break; + case 1: data = (cartridge.ram.read(addr) & 0xf3) | ((data & 3) << 2); break; + case 2: data = (cartridge.ram.read(addr) & 0xcf) | ((data & 3) << 4); break; + case 3: data = (cartridge.ram.read(addr) & 0x3f) | ((data & 3) << 6); break; + } + } + + cartridge.ram.write(addr, data); +} + +#endif diff --git a/snes/chip/sa1/memory/memory.hpp b/snes/chip/sa1/memory/memory.hpp new file mode 100755 index 00000000..ffb9e9f6 --- /dev/null +++ b/snes/chip/sa1/memory/memory.hpp @@ -0,0 +1,19 @@ +uint8 bus_read(unsigned addr); +void bus_write(unsigned addr, uint8 data); +uint8 vbr_read(unsigned addr); + +alwaysinline void op_io(); +alwaysinline uint8 op_read(unsigned addr); +alwaysinline void op_write(unsigned addr, uint8 data); + +uint8 mmc_read(unsigned addr); +void mmc_write(unsigned addr, uint8 data); + +uint8 mmc_cpu_read(unsigned addr); +void mmc_cpu_write(unsigned addr, uint8 data); + +uint8 mmc_sa1_read(unsigned addr); +void mmc_sa1_write(unsigned addr, uint8 data); + +uint8 bitmap_read(unsigned addr); +void bitmap_write(unsigned addr, uint8 data); diff --git a/snes/chip/sa1/mmio/mmio.cpp b/snes/chip/sa1/mmio/mmio.cpp new file mode 100755 index 00000000..c4a894b0 --- /dev/null +++ b/snes/chip/sa1/mmio/mmio.cpp @@ -0,0 +1,554 @@ +#ifdef SA1_CPP + +//(CCNT) SA-1 control +void SA1::mmio_w2200(uint8 data) { + if(mmio.sa1_resb && !(data & 0x80)) { + //reset SA-1 CPU + regs.pc.w = mmio.crv; + regs.pc.b = 0x00; + } + + mmio.sa1_irq = (data & 0x80); + mmio.sa1_rdyb = (data & 0x40); + mmio.sa1_resb = (data & 0x20); + mmio.sa1_nmi = (data & 0x10); + mmio.smeg = (data & 0x0f); + + if(mmio.sa1_irq) { + mmio.sa1_irqfl = true; + if(mmio.sa1_irqen) mmio.sa1_irqcl = 0; + } + + if(mmio.sa1_nmi) { + mmio.sa1_nmifl = true; + if(mmio.sa1_nmien) mmio.sa1_nmicl = 0; + } +} + +//(SIE) S-CPU interrupt enable +void SA1::mmio_w2201(uint8 data) { + if(!mmio.cpu_irqen && (data & 0x80)) { + if(mmio.cpu_irqfl) { + mmio.cpu_irqcl = 0; + cpu.regs.irq = 1; + } + } + + if(!mmio.chdma_irqen && (data & 0x20)) { + if(mmio.chdma_irqfl) { + mmio.chdma_irqcl = 0; + cpu.regs.irq = 1; + } + } + + mmio.cpu_irqen = (data & 0x80); + mmio.chdma_irqen = (data & 0x20); +} + +//(SIC) S-CPU interrupt clear +void SA1::mmio_w2202(uint8 data) { + mmio.cpu_irqcl = (data & 0x80); + mmio.chdma_irqcl = (data & 0x20); + + if(mmio.cpu_irqcl ) mmio.cpu_irqfl = false; + if(mmio.chdma_irqcl) mmio.chdma_irqfl = false; + + if(!mmio.cpu_irqfl && !mmio.chdma_irqfl) cpu.regs.irq = 0; +} + +//(CRV) SA-1 reset vector +void SA1::mmio_w2203(uint8 data) { mmio.crv = (mmio.crv & 0xff00) | data; } +void SA1::mmio_w2204(uint8 data) { mmio.crv = (data << 8) | (mmio.crv & 0xff); } + +//(CNV) SA-1 NMI vector +void SA1::mmio_w2205(uint8 data) { mmio.cnv = (mmio.cnv & 0xff00) | data; } +void SA1::mmio_w2206(uint8 data) { mmio.cnv = (data << 8) | (mmio.cnv & 0xff); } + +//(CIV) SA-1 IRQ vector +void SA1::mmio_w2207(uint8 data) { mmio.civ = (mmio.civ & 0xff00) | data; } +void SA1::mmio_w2208(uint8 data) { mmio.civ = (data << 8) | (mmio.civ & 0xff); } + +//(SCNT) S-CPU control +void SA1::mmio_w2209(uint8 data) { + mmio.cpu_irq = (data & 0x80); + mmio.cpu_ivsw = (data & 0x40); + mmio.cpu_nvsw = (data & 0x10); + mmio.cmeg = (data & 0x0f); + + if(mmio.cpu_irq) { + mmio.cpu_irqfl = true; + if(mmio.cpu_irqen) { + mmio.cpu_irqcl = 0; + cpu.regs.irq = 1; + } + } +} + +//(CIE) SA-1 interrupt enable +void SA1::mmio_w220a(uint8 data) { + if(!mmio.sa1_irqen && (data & 0x80) && mmio.sa1_irqfl ) mmio.sa1_irqcl = 0; + if(!mmio.timer_irqen && (data & 0x40) && mmio.timer_irqfl) mmio.timer_irqcl = 0; + if(!mmio.dma_irqen && (data & 0x20) && mmio.dma_irqfl ) mmio.dma_irqcl = 0; + if(!mmio.sa1_nmien && (data & 0x10) && mmio.sa1_nmifl ) mmio.sa1_nmicl = 0; + + mmio.sa1_irqen = (data & 0x80); + mmio.timer_irqen = (data & 0x40); + mmio.dma_irqen = (data & 0x20); + mmio.sa1_nmien = (data & 0x10); +} + +//(CIC) SA-1 interrupt clear +void SA1::mmio_w220b(uint8 data) { + mmio.sa1_irqcl = (data & 0x80); + mmio.timer_irqcl = (data & 0x40); + mmio.dma_irqcl = (data & 0x20); + mmio.sa1_nmicl = (data & 0x10); + + if(mmio.sa1_irqcl) mmio.sa1_irqfl = false; + if(mmio.timer_irqcl) mmio.timer_irqfl = false; + if(mmio.dma_irqcl) mmio.dma_irqfl = false; + if(mmio.sa1_nmicl) mmio.sa1_nmifl = false; +} + +//(SNV) S-CPU NMI vector +void SA1::mmio_w220c(uint8 data) { mmio.snv = (mmio.snv & 0xff00) | data; } +void SA1::mmio_w220d(uint8 data) { mmio.snv = (data << 8) | (mmio.snv & 0xff); } + +//(SIV) S-CPU IRQ vector +void SA1::mmio_w220e(uint8 data) { mmio.siv = (mmio.siv & 0xff00) | data; } +void SA1::mmio_w220f(uint8 data) { mmio.siv = (data << 8) | (mmio.siv & 0xff); } + +//(TMC) H/V timer control +void SA1::mmio_w2210(uint8 data) { + mmio.hvselb = (data & 0x80); + mmio.ven = (data & 0x02); + mmio.hen = (data & 0x01); +} + +//(CTR) SA-1 timer restart +void SA1::mmio_w2211(uint8 data) { + status.vcounter = 0; + status.hcounter = 0; +} + +//(HCNT) H-count +void SA1::mmio_w2212(uint8 data) { mmio.hcnt = (mmio.hcnt & 0xff00) | (data << 0); } +void SA1::mmio_w2213(uint8 data) { mmio.hcnt = (mmio.hcnt & 0x00ff) | (data << 8); } + +//(VCNT) V-count +void SA1::mmio_w2214(uint8 data) { mmio.vcnt = (mmio.vcnt & 0xff00) | (data << 0); } +void SA1::mmio_w2215(uint8 data) { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8); } + +//(CXB) Super MMC bank C +void SA1::mmio_w2220(uint8 data) { + mmio.cbmode = (data & 0x80); + mmio.cb = (data & 0x07); +} + +//(DXB) Super MMC bank D +void SA1::mmio_w2221(uint8 data) { + mmio.dbmode = (data & 0x80); + mmio.db = (data & 0x07); +} + +//(EXB) Super MMC bank E +void SA1::mmio_w2222(uint8 data) { + mmio.ebmode = (data & 0x80); + mmio.eb = (data & 0x07); +} + +//(FXB) Super MMC bank F +void SA1::mmio_w2223(uint8 data) { + mmio.fbmode = (data & 0x80); + mmio.fb = (data & 0x07); +} + +//(BMAPS) S-CPU BW-RAM address mapping +void SA1::mmio_w2224(uint8 data) { + mmio.sbm = (data & 0x1f); +} + +//(BMAP) SA-1 BW-RAM address mapping +void SA1::mmio_w2225(uint8 data) { + mmio.sw46 = (data & 0x80); + mmio.cbm = (data & 0x7f); +} + +//(SWBE) S-CPU BW-RAM write enable +void SA1::mmio_w2226(uint8 data) { + mmio.swen = (data & 0x80); +} + +//(CWBE) SA-1 BW-RAM write enable +void SA1::mmio_w2227(uint8 data) { + mmio.cwen = (data & 0x80); +} + +//(BWPA) BW-RAM write-protected area +void SA1::mmio_w2228(uint8 data) { + mmio.bwp = (data & 0x0f); +} + +//(SIWP) S-CPU I-RAM write protection +void SA1::mmio_w2229(uint8 data) { + mmio.siwp = data; +} + +//(CIWP) SA-1 I-RAM write protection +void SA1::mmio_w222a(uint8 data) { + mmio.ciwp = data; +} + +//(DCNT) DMA control +void SA1::mmio_w2230(uint8 data) { + mmio.dmaen = (data & 0x80); + mmio.dprio = (data & 0x40); + mmio.cden = (data & 0x20); + mmio.cdsel = (data & 0x10); + mmio.dd = (data & 0x04); + mmio.sd = (data & 0x03); + + if(mmio.dmaen == 0) dma.line = 0; +} + +//(CDMA) character conversion DMA parameters +void SA1::mmio_w2231(uint8 data) { + mmio.chdend = (data & 0x80); + mmio.dmasize = (data >> 2) & 7; + mmio.dmacb = (data & 0x03); + + if(mmio.chdend) cpubwram.dma = false; + if(mmio.dmasize > 5) mmio.dmasize = 5; + if(mmio.dmacb > 2) mmio.dmacb = 2; +} + +//(SDA) DMA source device start address +void SA1::mmio_w2232(uint8 data) { mmio.dsa = (mmio.dsa & 0xffff00) | (data << 0); } +void SA1::mmio_w2233(uint8 data) { mmio.dsa = (mmio.dsa & 0xff00ff) | (data << 8); } +void SA1::mmio_w2234(uint8 data) { mmio.dsa = (mmio.dsa & 0x00ffff) | (data << 16); } + +//(DDA) DMA destination start address +void SA1::mmio_w2235(uint8 data) { + mmio.dda = (mmio.dda & 0xffff00) | (data << 0); +} + +void SA1::mmio_w2236(uint8 data) { + mmio.dda = (mmio.dda & 0xff00ff) | (data << 8); + + if(mmio.dmaen == true) { + if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) { + dma_normal(); + } else if(mmio.cden == 1 && mmio.cdsel == 1) { + dma_cc1(); + } + } +} + +void SA1::mmio_w2237(uint8 data) { + mmio.dda = (mmio.dda & 0x00ffff) | (data << 16); + + if(mmio.dmaen == true) { + if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) { + dma_normal(); + } + } +} + +//(DTC) DMA terminal counter +void SA1::mmio_w2238(uint8 data) { mmio.dtc = (mmio.dtc & 0xff00) | (data << 0); } +void SA1::mmio_w2239(uint8 data) { mmio.dtc = (mmio.dtc & 0x00ff) | (data << 8); } + +//(BBF) BW-RAM bitmap format +void SA1::mmio_w223f(uint8 data) { + mmio.bbf = (data & 0x80); +} + +//(BRF) bitmap register files +void SA1::mmio_w2240(uint8 data) { mmio.brf[ 0] = data; } +void SA1::mmio_w2241(uint8 data) { mmio.brf[ 1] = data; } +void SA1::mmio_w2242(uint8 data) { mmio.brf[ 2] = data; } +void SA1::mmio_w2243(uint8 data) { mmio.brf[ 3] = data; } +void SA1::mmio_w2244(uint8 data) { mmio.brf[ 4] = data; } +void SA1::mmio_w2245(uint8 data) { mmio.brf[ 5] = data; } +void SA1::mmio_w2246(uint8 data) { mmio.brf[ 6] = data; } +void SA1::mmio_w2247(uint8 data) { mmio.brf[ 7] = data; + if(mmio.dmaen == true) { + if(mmio.cden == 1 && mmio.cdsel == 0) { + dma_cc2(); + } + } +} + +void SA1::mmio_w2248(uint8 data) { mmio.brf[ 8] = data; } +void SA1::mmio_w2249(uint8 data) { mmio.brf[ 9] = data; } +void SA1::mmio_w224a(uint8 data) { mmio.brf[10] = data; } +void SA1::mmio_w224b(uint8 data) { mmio.brf[11] = data; } +void SA1::mmio_w224c(uint8 data) { mmio.brf[12] = data; } +void SA1::mmio_w224d(uint8 data) { mmio.brf[13] = data; } +void SA1::mmio_w224e(uint8 data) { mmio.brf[14] = data; } +void SA1::mmio_w224f(uint8 data) { mmio.brf[15] = data; + if(mmio.dmaen == true) { + if(mmio.cden == 1 && mmio.cdsel == 0) { + dma_cc2(); + } + } +} + +//(MCNT) arithmetic control +void SA1::mmio_w2250(uint8 data) { + mmio.acm = (data & 0x02); + mmio.md = (data & 0x01); + + if(mmio.acm) mmio.mr = 0; +} + +//(MAL) multiplicand / dividend low +void SA1::mmio_w2251(uint8 data) { + mmio.ma = (mmio.ma & 0xff00) | data; +} + +//(MAH) multiplicand / dividend high +void SA1::mmio_w2252(uint8 data) { + mmio.ma = (data << 8) | (mmio.ma & 0x00ff); +} + +//(MBL) multiplier / divisor low +void SA1::mmio_w2253(uint8 data) { + mmio.mb = (mmio.mb & 0xff00) | data; +} + +//(MBH) multiplier / divisor high +//multiplication / cumulative sum only resets MB +//division resets both MA and MB +void SA1::mmio_w2254(uint8 data) { + mmio.mb = (data << 8) | (mmio.mb & 0x00ff); + + if(mmio.acm == 0) { + if(mmio.md == 0) { + //signed multiplication + mmio.mr = (int16)mmio.ma * (int16)mmio.mb; + mmio.mb = 0; + } else { + //unsigned division + if(mmio.mb == 0) { + mmio.mr = 0; + } else { + int16 quotient = (int16)mmio.ma / (uint16)mmio.mb; + uint16 remainder = (int16)mmio.ma % (uint16)mmio.mb; + mmio.mr = (remainder << 16) | quotient; + } + mmio.ma = 0; + mmio.mb = 0; + } + } else { + //sigma (accumulative multiplication) + mmio.mr += (int16)mmio.ma * (int16)mmio.mb; + mmio.overflow = (mmio.mr >= (1ULL << 40)); + mmio.mr &= (1ULL << 40) - 1; + mmio.mb = 0; + } +} + +//(VBD) variable-length bit processing +void SA1::mmio_w2258(uint8 data) { + mmio.hl = (data & 0x80); + mmio.vb = (data & 0x0f); + if(mmio.vb == 0) mmio.vb = 16; + + if(mmio.hl == 0) { + //fixed mode + mmio.vbit += mmio.vb; + mmio.va += (mmio.vbit >> 3); + mmio.vbit &= 7; + } +} + +//(VDA) variable-length bit game pak ROM start address +void SA1::mmio_w2259(uint8 data) { mmio.va = (mmio.va & 0xffff00) | (data << 0); } +void SA1::mmio_w225a(uint8 data) { mmio.va = (mmio.va & 0xff00ff) | (data << 8); } +void SA1::mmio_w225b(uint8 data) { mmio.va = (mmio.va & 0x00ffff) | (data << 16); mmio.vbit = 0; } + +//(SFR) S-CPU flag read +uint8 SA1::mmio_r2300() { + uint8 data; + data = mmio.cpu_irqfl << 7; + data |= mmio.cpu_ivsw << 6; + data |= mmio.chdma_irqfl << 5; + data |= mmio.cpu_nvsw << 4; + data |= mmio.cmeg; + return data; +} + +//(CFR) SA-1 flag read +uint8 SA1::mmio_r2301() { + uint8 data; + data = mmio.sa1_irqfl << 7; + data |= mmio.timer_irqfl << 6; + data |= mmio.dma_irqfl << 5; + data |= mmio.sa1_nmifl << 4; + data |= mmio.smeg; + return data; +} + +//(HCR) hcounter read +uint8 SA1::mmio_r2302() { + //latch counters + mmio.hcr = status.hcounter >> 2; + mmio.vcr = status.vcounter; + return mmio.hcr >> 0; } +uint8 SA1::mmio_r2303() { return mmio.hcr >> 8; } + +//(VCR) vcounter read +uint8 SA1::mmio_r2304() { return mmio.vcr >> 0; } +uint8 SA1::mmio_r2305() { return mmio.vcr >> 8; } + +//(MR) arithmetic result +uint8 SA1::mmio_r2306() { return mmio.mr >> 0; } +uint8 SA1::mmio_r2307() { return mmio.mr >> 8; } +uint8 SA1::mmio_r2308() { return mmio.mr >> 16; } +uint8 SA1::mmio_r2309() { return mmio.mr >> 24; } +uint8 SA1::mmio_r230a() { return mmio.mr >> 32; } + +//(OF) arithmetic overflow flag +uint8 SA1::mmio_r230b() { return mmio.overflow << 7; } + +//(VDPL) variable-length data read port low +uint8 SA1::mmio_r230c() { + uint32 data = (vbr_read(mmio.va + 0) << 0) + | (vbr_read(mmio.va + 1) << 8) + | (vbr_read(mmio.va + 2) << 16); + data >>= mmio.vbit; + return data >> 0; +} + +//(VDPH) variable-length data read port high +uint8 SA1::mmio_r230d() { + uint32 data = (vbr_read(mmio.va + 0) << 0) + | (vbr_read(mmio.va + 1) << 8) + | (vbr_read(mmio.va + 2) << 16); + data >>= mmio.vbit; + + if(mmio.hl == 1) { + //auto-increment mode + mmio.vbit += mmio.vb; + mmio.va += (mmio.vbit >> 3); + mmio.vbit &= 7; + } + + return data >> 8; +} + +//(VC) version code register +uint8 SA1::mmio_r230e() { + return 0x01; //true value unknown +} + +uint8 SA1::mmio_read(unsigned addr) { + (co_active() == cpu.thread ? cpu.synchronize_coprocessors() : synchronize_cpu()); + addr &= 0xffff; + + switch(addr) { + case 0x2300: return mmio_r2300(); + case 0x2301: return mmio_r2301(); + case 0x2302: return mmio_r2302(); + case 0x2303: return mmio_r2303(); + case 0x2304: return mmio_r2304(); + case 0x2305: return mmio_r2305(); + case 0x2306: return mmio_r2306(); + case 0x2307: return mmio_r2307(); + case 0x2308: return mmio_r2308(); + case 0x2309: return mmio_r2309(); + case 0x230a: return mmio_r230a(); + case 0x230b: return mmio_r230b(); + case 0x230c: return mmio_r230c(); + case 0x230d: return mmio_r230d(); + case 0x230e: return mmio_r230e(); + } + + return 0x00; +} + +void SA1::mmio_write(unsigned addr, uint8 data) { + (co_active() == cpu.thread ? cpu.synchronize_coprocessors() : synchronize_cpu()); + addr &= 0xffff; + + switch(addr) { + case 0x2200: return mmio_w2200(data); + case 0x2201: return mmio_w2201(data); + case 0x2202: return mmio_w2202(data); + case 0x2203: return mmio_w2203(data); + case 0x2204: return mmio_w2204(data); + case 0x2205: return mmio_w2205(data); + case 0x2206: return mmio_w2206(data); + case 0x2207: return mmio_w2207(data); + case 0x2208: return mmio_w2208(data); + case 0x2209: return mmio_w2209(data); + case 0x220a: return mmio_w220a(data); + case 0x220b: return mmio_w220b(data); + case 0x220c: return mmio_w220c(data); + case 0x220d: return mmio_w220d(data); + case 0x220e: return mmio_w220e(data); + case 0x220f: return mmio_w220f(data); + + case 0x2210: return mmio_w2210(data); + case 0x2211: return mmio_w2211(data); + case 0x2212: return mmio_w2212(data); + case 0x2213: return mmio_w2213(data); + case 0x2214: return mmio_w2214(data); + case 0x2215: return mmio_w2215(data); + + case 0x2220: return mmio_w2220(data); + case 0x2221: return mmio_w2221(data); + case 0x2222: return mmio_w2222(data); + case 0x2223: return mmio_w2223(data); + case 0x2224: return mmio_w2224(data); + case 0x2225: return mmio_w2225(data); + case 0x2226: return mmio_w2226(data); + case 0x2227: return mmio_w2227(data); + case 0x2228: return mmio_w2228(data); + case 0x2229: return mmio_w2229(data); + case 0x222a: return mmio_w222a(data); + + case 0x2230: return mmio_w2230(data); + case 0x2231: return mmio_w2231(data); + case 0x2232: return mmio_w2232(data); + case 0x2233: return mmio_w2233(data); + case 0x2234: return mmio_w2234(data); + case 0x2235: return mmio_w2235(data); + case 0x2236: return mmio_w2236(data); + case 0x2237: return mmio_w2237(data); + case 0x2238: return mmio_w2238(data); + case 0x2239: return mmio_w2239(data); + + case 0x223f: return mmio_w223f(data); + case 0x2240: return mmio_w2240(data); + case 0x2241: return mmio_w2241(data); + case 0x2242: return mmio_w2242(data); + case 0x2243: return mmio_w2243(data); + case 0x2244: return mmio_w2244(data); + case 0x2245: return mmio_w2245(data); + case 0x2246: return mmio_w2246(data); + case 0x2247: return mmio_w2247(data); + case 0x2248: return mmio_w2248(data); + case 0x2249: return mmio_w2249(data); + case 0x224a: return mmio_w224a(data); + case 0x224b: return mmio_w224b(data); + case 0x224c: return mmio_w224c(data); + case 0x224d: return mmio_w224d(data); + case 0x224e: return mmio_w224e(data); + case 0x224f: return mmio_w224f(data); + + case 0x2250: return mmio_w2250(data); + case 0x2251: return mmio_w2251(data); + case 0x2252: return mmio_w2252(data); + case 0x2253: return mmio_w2253(data); + case 0x2254: return mmio_w2254(data); + + case 0x2258: return mmio_w2258(data); + case 0x2259: return mmio_w2259(data); + case 0x225a: return mmio_w225a(data); + case 0x225b: return mmio_w225b(data); + } +} + +#endif diff --git a/snes/chip/sa1/mmio/mmio.hpp b/snes/chip/sa1/mmio/mmio.hpp new file mode 100755 index 00000000..4eaa1468 --- /dev/null +++ b/snes/chip/sa1/mmio/mmio.hpp @@ -0,0 +1,255 @@ +uint8 mmio_read(unsigned addr); +void mmio_write(unsigned addr, uint8 data); + +struct MMIO { + //$2200 CCNT + bool sa1_irq; + bool sa1_rdyb; + bool sa1_resb; + bool sa1_nmi; + uint8 smeg; + + //$2201 SIE + bool cpu_irqen; + bool chdma_irqen; + + //$2202 SIC + bool cpu_irqcl; + bool chdma_irqcl; + + //$2203,$2204 CRV + uint16 crv; + + //$2205,$2206 CNV + uint16 cnv; + + //$2207,$2208 CIV + uint16 civ; + + //$2209 SCNT + bool cpu_irq; + bool cpu_ivsw; + bool cpu_nvsw; + uint8 cmeg; + + //$220a CIE + bool sa1_irqen; + bool timer_irqen; + bool dma_irqen; + bool sa1_nmien; + + //$220b CIC + bool sa1_irqcl; + bool timer_irqcl; + bool dma_irqcl; + bool sa1_nmicl; + + //$220c,$220d SNV + uint16 snv; + + //$220e,$220f SIV + uint16 siv; + + //$2210 TMC + bool hvselb; + bool ven; + bool hen; + + //$2212,$2213 + uint16 hcnt; + + //$2214,$2215 + uint16 vcnt; + + //$2220 CXB + bool cbmode; + unsigned cb; + + //$2221 DXB + bool dbmode; + unsigned db; + + //$2222 EXB + bool ebmode; + unsigned eb; + + //$2223 FXB + bool fbmode; + unsigned fb; + + //$2224 BMAPS + uint8 sbm; + + //$2225 BMAP + bool sw46; + uint8 cbm; + + //$2226 SBWE + bool swen; + + //$2227 CBWE + bool cwen; + + //$2228 BWPA + uint8 bwp; + + //$2229 SIWP + uint8 siwp; + + //$222a CIWP + uint8 ciwp; + + //$2230 DCNT + bool dmaen; + bool dprio; + bool cden; + bool cdsel; + bool dd; + uint8 sd; + + //$2231 CDMA + bool chdend; + uint8 dmasize; + uint8 dmacb; + + //$2232-$2234 SDA + uint32 dsa; + + //$2235-$2237 DDA + uint32 dda; + + //$2238,$2239 DTC + uint16 dtc; + + //$223f BBF + bool bbf; + + //$2240-224f BRF + uint8 brf[16]; + + //$2250 MCNT + bool acm; + bool md; + + //$2251,$2252 MA + uint16 ma; + + //$2253,$2254 MB + uint16 mb; + + //$2258 VBD + bool hl; + uint8 vb; + + //$2259-$225b VDA + uint32 va; + uint8 vbit; + + //$2300 SFR + bool cpu_irqfl; + bool chdma_irqfl; + + //$2301 CFR + bool sa1_irqfl; + bool timer_irqfl; + bool dma_irqfl; + bool sa1_nmifl; + + //$2302,$2303 HCR + uint16 hcr; + + //$2304,$2305 VCR + uint16 vcr; + + //$2306-230a MR + uint64 mr; + + //$230b OF + bool overflow; +} mmio; + +void mmio_w2200(uint8); //CCNT +void mmio_w2201(uint8); //SIE +void mmio_w2202(uint8); //SIC +void mmio_w2203(uint8); //CRVL +void mmio_w2204(uint8); //CRVH +void mmio_w2205(uint8); //CNVL +void mmio_w2206(uint8); //CNVH +void mmio_w2207(uint8); //CIVL +void mmio_w2208(uint8); //CIVH +void mmio_w2209(uint8); //SCNT +void mmio_w220a(uint8); //CIE +void mmio_w220b(uint8); //CIC +void mmio_w220c(uint8); //SNVL +void mmio_w220d(uint8); //SNVH +void mmio_w220e(uint8); //SIVL +void mmio_w220f(uint8); //SIVH +void mmio_w2210(uint8); //TMC +void mmio_w2211(uint8); //CTR +void mmio_w2212(uint8); //HCNTL +void mmio_w2213(uint8); //HCNTH +void mmio_w2214(uint8); //VCNTL +void mmio_w2215(uint8); //VCNTH +void mmio_w2220(uint8); //CXB +void mmio_w2221(uint8); //DXB +void mmio_w2222(uint8); //EXB +void mmio_w2223(uint8); //FXB +void mmio_w2224(uint8); //BMAPS +void mmio_w2225(uint8); //BMAP +void mmio_w2226(uint8); //SBWE +void mmio_w2227(uint8); //CBWE +void mmio_w2228(uint8); //BWPA +void mmio_w2229(uint8); //SIWP +void mmio_w222a(uint8); //CIWP +void mmio_w2230(uint8); //DCNT +void mmio_w2231(uint8); //CDMA +void mmio_w2232(uint8); //SDAL +void mmio_w2233(uint8); //SDAH +void mmio_w2234(uint8); //SDAB +void mmio_w2235(uint8); //DDAL +void mmio_w2236(uint8); //DDAH +void mmio_w2237(uint8); //DDAB +void mmio_w2238(uint8); //DTCL +void mmio_w2239(uint8); //DTCH +void mmio_w223f(uint8); //BBF +void mmio_w2240(uint8); //BRF0 +void mmio_w2241(uint8); //BRF1 +void mmio_w2242(uint8); //BRF2 +void mmio_w2243(uint8); //BRF3 +void mmio_w2244(uint8); //BRF4 +void mmio_w2245(uint8); //BRF5 +void mmio_w2246(uint8); //BRF6 +void mmio_w2247(uint8); //BRF7 +void mmio_w2248(uint8); //BRF8 +void mmio_w2249(uint8); //BRF9 +void mmio_w224a(uint8); //BRFA +void mmio_w224b(uint8); //BRFB +void mmio_w224c(uint8); //BRFC +void mmio_w224d(uint8); //BRFD +void mmio_w224e(uint8); //BRFE +void mmio_w224f(uint8); //BRFF +void mmio_w2250(uint8); //MCNT +void mmio_w2251(uint8); //MAL +void mmio_w2252(uint8); //MAH +void mmio_w2253(uint8); //MBL +void mmio_w2254(uint8); //MBH +void mmio_w2258(uint8); //VBD +void mmio_w2259(uint8); //VDAL +void mmio_w225a(uint8); //VDAH +void mmio_w225b(uint8); //VDAB + +uint8 mmio_r2300(); //SFR +uint8 mmio_r2301(); //CFR +uint8 mmio_r2302(); //HCRL +uint8 mmio_r2303(); //HCRH +uint8 mmio_r2304(); //VCRL +uint8 mmio_r2305(); //VCRH +uint8 mmio_r2306(); //MR [00-07] +uint8 mmio_r2307(); //MR [08-15] +uint8 mmio_r2308(); //MR [16-23] +uint8 mmio_r2309(); //MR [24-31] +uint8 mmio_r230a(); //MR [32-40] +uint8 mmio_r230b(); //OF +uint8 mmio_r230c(); //VDPL +uint8 mmio_r230d(); //VDPH +uint8 mmio_r230e(); //VC diff --git a/snes/chip/sa1/sa1.cpp b/snes/chip/sa1/sa1.cpp new file mode 100755 index 00000000..9620e4f9 --- /dev/null +++ b/snes/chip/sa1/sa1.cpp @@ -0,0 +1,331 @@ +#include + +#define SA1_CPP +namespace SNES { + +SA1 sa1; + +#include "serialization.cpp" +#include "bus/bus.cpp" +#include "dma/dma.cpp" +#include "memory/memory.cpp" +#include "mmio/mmio.cpp" + +void SA1::Enter() { sa1.enter(); } + +void SA1::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(mmio.sa1_rdyb || mmio.sa1_resb) { + //SA-1 co-processor is asleep + tick(); + synchronize_cpu(); + continue; + } + + if(status.interrupt_pending) { + status.interrupt_pending = false; + op_irq(); + continue; + } + + (this->*opcode_table[op_readpc()])(); + } +} + +void SA1::op_irq() { + op_read(regs.pc.d); + op_io(); + if(!regs.e) op_writestack(regs.pc.b); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + op_writestack(regs.e ? (regs.p & ~0x10) : regs.p); + regs.pc.w = regs.vector; + regs.pc.b = 0x00; + regs.p.i = 1; + regs.p.d = 0; +} + +void SA1::last_cycle() { + if(mmio.sa1_nmi && !mmio.sa1_nmicl) { + status.interrupt_pending = true; + regs.vector = mmio.cnv; + mmio.sa1_nmifl = true; + mmio.sa1_nmicl = 1; + regs.wai = false; + } else if(!regs.p.i) { + if(mmio.timer_irqen && !mmio.timer_irqcl) { + status.interrupt_pending = true; + regs.vector = mmio.civ; + mmio.timer_irqfl = true; + regs.wai = false; + } else if(mmio.dma_irqen && !mmio.dma_irqcl) { + status.interrupt_pending = true; + regs.vector = mmio.civ; + mmio.dma_irqfl = true; + regs.wai = false; + } else if(mmio.sa1_irq && !mmio.sa1_irqcl) { + status.interrupt_pending = true; + regs.vector = mmio.civ; + mmio.sa1_irqfl = true; + regs.wai = false; + } + } +} + +bool SA1::interrupt_pending() { + return status.interrupt_pending; +} + +void SA1::tick() { + step(2); + if(++status.tick_counter == 0) synchronize_cpu(); + + //adjust counters: + //note that internally, status counters are in clocks; + //whereas MMIO register counters are in dots (4 clocks = 1 dot) + if(mmio.hvselb == 0) { + //HV timer + status.hcounter += 2; + if(status.hcounter >= 1364) { + status.hcounter = 0; + if(++status.vcounter >= status.scanlines) status.vcounter = 0; + } + } else { + //linear timer + status.hcounter += 2; + status.vcounter += (status.hcounter >> 11); + status.hcounter &= 0x07ff; + status.vcounter &= 0x01ff; + } + + //test counters for timer IRQ + switch((mmio.ven << 1) + (mmio.hen << 0)) { + case 0: break; + case 1: if(status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break; + case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) trigger_irq(); break; + case 3: if(status.vcounter == mmio.hcnt && status.hcounter == (mmio.hcnt << 2)) trigger_irq(); break; + } +} + +void SA1::trigger_irq() { + mmio.timer_irqfl = true; + if(mmio.timer_irqen) mmio.timer_irqcl = 0; +} + +void SA1::init() { +} + +void SA1::load() { +} + +void SA1::unload() { +} + +void SA1::power() { + regs.a = regs.x = regs.y = 0x0000; + regs.s = 0x01ff; + reset(); +} + +void SA1::reset() { + create(SA1::Enter, system.cpu_frequency()); + + cpubwram.dma = false; + for(unsigned addr = 0; addr < iram.size(); addr++) { + iram.write(addr, 0x00); + } + + regs.pc.d = 0x000000; + regs.x.h = 0x00; + regs.y.h = 0x00; + regs.s.h = 0x01; + regs.d = 0x0000; + regs.db = 0x00; + regs.p = 0x34; + regs.e = 1; + regs.mdr = 0x00; + regs.wai = false; + regs.vector = 0x0000; + CPUcore::update_table(); + + status.tick_counter = 0; + + status.interrupt_pending = false; + + status.scanlines = (system.region() == System::Region::NTSC ? 262 : 312); + status.vcounter = 0; + status.hcounter = 0; + + dma.line = 0; + + //$2200 CCNT + mmio.sa1_irq = false; + mmio.sa1_rdyb = false; + mmio.sa1_resb = true; + mmio.sa1_nmi = false; + mmio.smeg = 0; + + //$2201 SIE + mmio.cpu_irqen = false; + mmio.chdma_irqen = false; + + //$2202 SIC + mmio.cpu_irqcl = false; + mmio.chdma_irqcl = false; + + //$2203,$2204 CRV + mmio.crv = 0x0000; + + //$2205,$2206 CNV + mmio.cnv = 0x0000; + + //$2207,$2208 CIV + mmio.civ = 0x0000; + + //$2209 SCNT + mmio.cpu_irq = false; + mmio.cpu_ivsw = false; + mmio.cpu_nvsw = false; + mmio.cmeg = 0; + + //$220a CIE + mmio.sa1_irqen = false; + mmio.timer_irqen = false; + mmio.dma_irqen = false; + mmio.sa1_nmien = false; + + //$220b CIC + mmio.sa1_irqcl = false; + mmio.timer_irqcl = false; + mmio.dma_irqcl = false; + mmio.sa1_nmicl = false; + + //$220c,$220d SNV + mmio.snv = 0x0000; + + //$220e,$220f SIV + mmio.siv = 0x0000; + + //$2210 + mmio.hvselb = false; + mmio.ven = false; + mmio.hen = false; + + //$2212,$2213 HCNT + mmio.hcnt = 0x0000; + + //$2214,$2215 VCNT + mmio.vcnt = 0x0000; + + //$2220-2223 CXB, DXB, EXB, FXB + mmio.cbmode = 1; + mmio.dbmode = 1; + mmio.ebmode = 1; + mmio.fbmode = 1; + + mmio.cb = 0x00; + mmio.db = 0x01; + mmio.eb = 0x00; + mmio.fb = 0x01; + + //$2224 BMAPS + mmio.sbm = 0x00; + + //$2225 BMAP + mmio.sw46 = false; + mmio.cbm = 0x00; + + //$2226 SWBE + mmio.swen = false; + + //$2227 CWBE + mmio.cwen = false; + + //$2228 BWPA + mmio.bwp = 0x0f; + + //$2229 SIWP + mmio.siwp = 0x00; + + //$222a CIWP + mmio.ciwp = 0x00; + + //$2230 DCNT + mmio.dmaen = false; + mmio.dprio = false; + mmio.cden = false; + mmio.cdsel = false; + mmio.dd = 0; + mmio.sd = 0; + + //$2231 CDMA + mmio.chdend = false; + mmio.dmasize = 0; + mmio.dmacb = 0; + + //$2232-$2234 SDA + mmio.dsa = 0x000000; + + //$2235-$2237 DDA + mmio.dda = 0x000000; + + //$2238,$2239 DTC + mmio.dtc = 0x0000; + + //$223f BBF + mmio.bbf = 0; + + //$2240-$224f BRF + for(unsigned i = 0; i < 16; i++) { + mmio.brf[i] = 0x00; + } + + //$2250 MCNT + mmio.acm = 0; + mmio.md = 0; + + //$2251,$2252 MA + mmio.ma = 0x0000; + + //$2253,$2254 MB + mmio.mb = 0x0000; + + //$2258 VBD + mmio.hl = false; + mmio.vb = 16; + + //$2259-$225b + mmio.va = 0x000000; + mmio.vbit = 0; + + //$2300 SFR + mmio.cpu_irqfl = false; + mmio.chdma_irqfl = false; + + //$2301 CFR + mmio.sa1_irqfl = false; + mmio.timer_irqfl = false; + mmio.dma_irqfl = false; + mmio.sa1_nmifl = false; + + //$2302,$2303 HCR + mmio.hcr = 0x0000; + + //$2304,$2305 VCR + mmio.vcr = 0x0000; + + //$2306-$230a MR + mmio.mr = 0; + + //$230b + mmio.overflow = false; +} + +SA1::SA1() : iram(2048) { +} + +} diff --git a/snes/chip/sa1/sa1.hpp b/snes/chip/sa1/sa1.hpp new file mode 100755 index 00000000..732b2a85 --- /dev/null +++ b/snes/chip/sa1/sa1.hpp @@ -0,0 +1,37 @@ +class SA1 : public Coprocessor, public CPUcore { +public: + #include "bus/bus.hpp" + #include "dma/dma.hpp" + #include "memory/memory.hpp" + #include "mmio/mmio.hpp" + + struct Status { + uint8 tick_counter; + + bool interrupt_pending; + + uint16 scanlines; + uint16 vcounter; + uint16 hcounter; + } status; + + static void Enter(); + void enter(); + void tick(); + void op_irq(); + + alwaysinline void trigger_irq(); + alwaysinline void last_cycle(); + alwaysinline bool interrupt_pending(); + + void init(); + void load(); + void unload(); + void power(); + void reset(); + + void serialize(serializer&); + SA1(); +}; + +extern SA1 sa1; diff --git a/snes/chip/sa1/serialization.cpp b/snes/chip/sa1/serialization.cpp new file mode 100755 index 00000000..3d755883 --- /dev/null +++ b/snes/chip/sa1/serialization.cpp @@ -0,0 +1,148 @@ +#ifdef SA1_CPP + +void SA1::serialize(serializer &s) { + Processor::serialize(s); + CPUcore::core_serialize(s); + + //sa1.hpp + s.integer(status.tick_counter); + + s.integer(status.interrupt_pending); + + s.integer(status.scanlines); + s.integer(status.vcounter); + s.integer(status.hcounter); + + //bus/bus.hpp + s.array(iram.data(), iram.size()); + + s.integer(cpubwram.dma); + + //dma/dma.hpp + s.integer(dma.line); + + //mmio/mmio.hpp + s.integer(mmio.sa1_irq); + s.integer(mmio.sa1_rdyb); + s.integer(mmio.sa1_resb); + s.integer(mmio.sa1_nmi); + s.integer(mmio.smeg); + + s.integer(mmio.cpu_irqen); + s.integer(mmio.chdma_irqen); + + s.integer(mmio.cpu_irqcl); + s.integer(mmio.chdma_irqcl); + + s.integer(mmio.crv); + + s.integer(mmio.cnv); + + s.integer(mmio.civ); + + s.integer(mmio.cpu_irq); + s.integer(mmio.cpu_ivsw); + s.integer(mmio.cpu_nvsw); + s.integer(mmio.cmeg); + + s.integer(mmio.sa1_irqen); + s.integer(mmio.timer_irqen); + s.integer(mmio.dma_irqen); + s.integer(mmio.sa1_nmien); + + s.integer(mmio.sa1_irqcl); + s.integer(mmio.timer_irqcl); + s.integer(mmio.dma_irqcl); + s.integer(mmio.sa1_nmicl); + + s.integer(mmio.snv); + + s.integer(mmio.siv); + + s.integer(mmio.hvselb); + s.integer(mmio.ven); + s.integer(mmio.hen); + + s.integer(mmio.hcnt); + + s.integer(mmio.vcnt); + + s.integer(mmio.cbmode); + s.integer(mmio.cb); + + s.integer(mmio.dbmode); + s.integer(mmio.db); + + s.integer(mmio.ebmode); + s.integer(mmio.eb); + + s.integer(mmio.fbmode); + s.integer(mmio.fb); + + s.integer(mmio.sbm); + + s.integer(mmio.sw46); + s.integer(mmio.cbm); + + s.integer(mmio.swen); + + s.integer(mmio.cwen); + + s.integer(mmio.bwp); + + s.integer(mmio.siwp); + + s.integer(mmio.ciwp); + + s.integer(mmio.dmaen); + s.integer(mmio.dprio); + s.integer(mmio.cden); + s.integer(mmio.cdsel); + s.integer(mmio.dd); + s.integer(mmio.sd); + + s.integer(mmio.chdend); + s.integer(mmio.dmasize); + s.integer(mmio.dmacb); + + s.integer(mmio.dsa); + + s.integer(mmio.dda); + + s.integer(mmio.dtc); + + s.integer(mmio.bbf); + + s.array(mmio.brf); + + s.integer(mmio.acm); + s.integer(mmio.md); + + s.integer(mmio.ma); + + s.integer(mmio.mb); + + s.integer(mmio.hl); + s.integer(mmio.vb); + + s.integer(mmio.va); + s.integer(mmio.vbit); + + s.integer(mmio.cpu_irqfl); + s.integer(mmio.chdma_irqfl); + + s.integer(mmio.sa1_irqfl); + s.integer(mmio.timer_irqfl); + s.integer(mmio.dma_irqfl); + s.integer(mmio.sa1_nmifl); + + s.integer(mmio.hcr); + + s.integer(mmio.vcr); + + s.integer(mmio.mr); + + s.integer(mmio.overflow); +} + +#endif diff --git a/snes/chip/sdd1/decomp.cpp b/snes/chip/sdd1/decomp.cpp new file mode 100755 index 00000000..9975580f --- /dev/null +++ b/snes/chip/sdd1/decomp.cpp @@ -0,0 +1,287 @@ +//S-DD1 decompression algorithm implementation +//original code written by Andreas Naive (public domain license) +//bsnes port written by byuu + +//note: decompression module does not need to be serialized with bsnes +//this is because decompression only runs during DMA, and bsnes will complete +//any pending DMA transfers prior to serialization. + +//input manager + +void SDD1::Decomp::IM::init(unsigned offset_) { + offset = offset_; + bit_count = 4; +} + +uint8 SDD1::Decomp::IM::get_codeword(uint8 code_length) { + uint8 codeword; + uint8 comp_count; + + codeword = self.rom_read(offset) << bit_count; + bit_count++; + + if(codeword & 0x80) { + codeword |= self.rom_read(offset + 1) >> (9 - bit_count); + bit_count += code_length; + } + + if(bit_count & 0x08) { + offset++; + bit_count &= 0x07; + } + + return codeword; +} + +//golomb-code decoder + +const uint8 SDD1::Decomp::GCD::run_count[] = { + 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, + 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, + 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, + 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00, + 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03, + 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01, + 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02, + 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00, + 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07, + 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03, + 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05, + 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01, + 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06, + 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02, + 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04, + 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00, + 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f, + 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07, + 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b, + 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03, + 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d, + 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05, + 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09, + 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01, + 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e, + 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06, + 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a, + 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02, + 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, + 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, +}; + +void SDD1::Decomp::GCD::get_run_count(uint8 code_number, uint8 &mps_count, bool &lps_index) { + uint8 codeword = self.im.get_codeword(code_number); + + if(codeword & 0x80) { + lps_index = 1; + mps_count = run_count[codeword >> (code_number ^ 0x07)]; + } else { + mps_count = 1 << code_number; + } +} + +//bits generator + +void SDD1::Decomp::BG::init() { + mps_count = 0; + lps_index = 0; +} + +uint8 SDD1::Decomp::BG::get_bit(bool &end_of_run) { + if(!(mps_count || lps_index)) self.gcd.get_run_count(code_number, mps_count, lps_index); + + uint8 bit; + if(mps_count) { + bit = 0; + mps_count--; + } else { + bit = 1; + lps_index = 0; + } + + end_of_run = !(mps_count || lps_index); + return bit; +} + +//probability estimation module + +const SDD1::Decomp::PEM::State SDD1::Decomp::PEM::evolution_table[33] = { + { 0, 25, 25 }, + { 0, 2, 1 }, + { 0, 3, 1 }, + { 0, 4, 2 }, + { 0, 5, 3 }, + { 1, 6, 4 }, + { 1, 7, 5 }, + { 1, 8, 6 }, + { 1, 9, 7 }, + { 2, 10, 8 }, + { 2, 11, 9 }, + { 2, 12, 10 }, + { 2, 13, 11 }, + { 3, 14, 12 }, + { 3, 15, 13 }, + { 3, 16, 14 }, + { 3, 17, 15 }, + { 4, 18, 16 }, + { 4, 19, 17 }, + { 5, 20, 18 }, + { 5, 21, 19 }, + { 6, 22, 20 }, + { 6, 23, 21 }, + { 7, 24, 22 }, + { 7, 24, 23 }, + { 0, 26, 1 }, + { 1, 27, 2 }, + { 2, 28, 4 }, + { 3, 29, 8 }, + { 4, 30, 12 }, + { 5, 31, 16 }, + { 6, 32, 18 }, + { 7, 24, 22 }, +}; + +void SDD1::Decomp::PEM::init() { + for(unsigned i = 0; i < 32; i++) { + context_info[i].status = 0; + context_info[i].mps = 0; + } +} + +uint8 SDD1::Decomp::PEM::get_bit(uint8 context) { + ContextInfo &info = context_info[context]; + uint8 current_status = info.status; + uint8 current_mps = info.mps; + const State &s = SDD1::Decomp::PEM::evolution_table[current_status]; + + uint8 bit; + bool end_of_run; + switch(s.code_number) { + case 0: bit = self.bg0.get_bit(end_of_run); break; + case 1: bit = self.bg1.get_bit(end_of_run); break; + case 2: bit = self.bg2.get_bit(end_of_run); break; + case 3: bit = self.bg3.get_bit(end_of_run); break; + case 4: bit = self.bg4.get_bit(end_of_run); break; + case 5: bit = self.bg5.get_bit(end_of_run); break; + case 6: bit = self.bg6.get_bit(end_of_run); break; + case 7: bit = self.bg7.get_bit(end_of_run); break; + } + + if(end_of_run) { + if(bit) { + if(!(current_status & 0xfe)) info.mps ^= 0x01; + info.status = s.next_if_lps; + } else { + info.status = s.next_if_mps; + } + } + + return bit ^ current_mps; +} + +//context model + +void SDD1::Decomp::CM::init(unsigned offset) { + bitplanes_info = self.rom_read(offset) & 0xc0; + context_bits_info = self.rom_read(offset) & 0x30; + bit_number = 0; + for(unsigned i = 0; i < 8; i++) previous_bitplane_bits[i] = 0; + switch(bitplanes_info) { + case 0x00: current_bitplane = 1; break; + case 0x40: current_bitplane = 7; break; + case 0x80: current_bitplane = 3; break; + } +} + +uint8 SDD1::Decomp::CM::get_bit() { + switch(bitplanes_info) { + case 0x00: + current_bitplane ^= 0x01; + break; + case 0x40: + current_bitplane ^= 0x01; + if(!(bit_number & 0x7f)) current_bitplane = ((current_bitplane + 2) & 0x07); + break; + case 0x80: + current_bitplane ^= 0x01; + if(!(bit_number & 0x7f)) current_bitplane ^= 0x02; + break; + case 0xc0: + current_bitplane = bit_number & 0x07; + break; + } + + uint16 &context_bits = previous_bitplane_bits[current_bitplane]; + uint8 current_context = (current_bitplane & 0x01) << 4; + switch(context_bits_info) { + case 0x00: current_context |= ((context_bits & 0x01c0) >> 5) | (context_bits & 0x0001); break; + case 0x10: current_context |= ((context_bits & 0x0180) >> 5) | (context_bits & 0x0001); break; + case 0x20: current_context |= ((context_bits & 0x00c0) >> 5) | (context_bits & 0x0001); break; + case 0x30: current_context |= ((context_bits & 0x0180) >> 5) | (context_bits & 0x0003); break; + } + + uint8 bit = self.pem.get_bit(current_context); + context_bits <<= 1; + context_bits |= bit; + bit_number++; + return bit; +} + +//output logic + +void SDD1::Decomp::OL::init(unsigned offset) { + bitplanes_info = self.rom_read(offset) & 0xc0; + r0 = 0x01; +} + +uint8 SDD1::Decomp::OL::decompress() { + switch(bitplanes_info) { + case 0x00: case 0x40: case 0x80: + if(r0 == 0) { + r0 = ~r0; + return r2; + } + for(r0 = 0x80, r1 = 0, r2 = 0; r0; r0 >>= 1) { + if(self.cm.get_bit()) r1 |= r0; + if(self.cm.get_bit()) r2 |= r0; + } + return r1; + case 0xc0: + for(r0 = 0x01, r1 = 0; r0; r0 <<= 1) { + if(self.cm.get_bit()) r1 |= r0; + } + return r1; + } +} + +//core + +void SDD1::Decomp::init(unsigned offset) { + im.init(offset); + bg0.init(); + bg1.init(); + bg2.init(); + bg3.init(); + bg4.init(); + bg5.init(); + bg6.init(); + bg7.init(); + pem.init(); + cm.init(offset); + ol.init(offset); +} + +uint8 SDD1::Decomp::read() { + return ol.decompress(); +} + +uint8 SDD1::Decomp::rom_read(unsigned offset) { + return sdd1.rom_read(offset); +} + +SDD1::Decomp::Decomp() : im(*this), gcd(*this), + bg0(*this, 0), bg1(*this, 1), bg2(*this, 2), bg3(*this, 3), + bg4(*this, 4), bg5(*this, 5), bg6(*this, 6), bg7(*this, 7), + pem(*this), cm(*this), ol(*this) { +} diff --git a/snes/chip/sdd1/decomp.hpp b/snes/chip/sdd1/decomp.hpp new file mode 100755 index 00000000..6c83d1d9 --- /dev/null +++ b/snes/chip/sdd1/decomp.hpp @@ -0,0 +1,82 @@ +struct Decomp { + struct IM { //input manager + Decomp &self; + void init(unsigned offset); + uint8 get_codeword(uint8 code_length); + IM(SDD1::Decomp &self) : self(self) {} + private: + unsigned offset; + unsigned bit_count; + }; + + struct GCD { //golomb-code decoder + Decomp &self; + static const uint8 run_count[256]; + void get_run_count(uint8 code_number, uint8 &mps_count, bool &lps_index); + GCD(SDD1::Decomp &self) : self(self) {} + }; + + struct BG { //bits generator + Decomp &self; + void init(); + uint8 get_bit(bool &end_of_run); + BG(SDD1::Decomp &self, uint8 code_number) : self(self), code_number(code_number) {} + private: + const uint8 code_number; + uint8 mps_count; + bool lps_index; + }; + + struct PEM { //probability estimation module + Decomp &self; + void init(); + uint8 get_bit(uint8 context); + PEM(SDD1::Decomp &self) : self(self) {} + private: + struct State { + uint8 code_number; + uint8 next_if_mps; + uint8 next_if_lps; + }; + static const State evolution_table[33]; + struct ContextInfo { + uint8 status; + uint8 mps; + } context_info[32]; + }; + + struct CM { //context model + Decomp &self; + void init(unsigned offset); + uint8 get_bit(); + CM(SDD1::Decomp &self) : self(self) {} + private: + uint8 bitplanes_info; + uint8 context_bits_info; + uint8 bit_number; + uint8 current_bitplane; + uint16 previous_bitplane_bits[8]; + }; + + struct OL { //output logic + Decomp &self; + void init(unsigned offset); + uint8 decompress(); + OL(SDD1::Decomp &self) : self(self) {} + private: + uint8 bitplanes_info; + uint8 r0, r1, r2; + }; + + void init(unsigned offset); + uint8 read(); + uint8 rom_read(unsigned offset); + Decomp(); + + IM im; + GCD gcd; + BG bg0, bg1, bg2, bg3, bg4, bg5, bg6, bg7; + PEM pem; + CM cm; + OL ol; +}; diff --git a/snes/chip/sdd1/sdd1.cpp b/snes/chip/sdd1/sdd1.cpp new file mode 100755 index 00000000..054f6e31 --- /dev/null +++ b/snes/chip/sdd1/sdd1.cpp @@ -0,0 +1,149 @@ +#include + +#define SDD1_CPP +namespace SNES { + +SDD1 sdd1; + +#include "decomp.cpp" +#include "serialization.cpp" + +void SDD1::init() { +} + +void SDD1::load() { + //hook S-CPU DMA MMIO registers to gather information for struct dma[]; + //buffer address and transfer size information for use in SDD1::mcu_read() + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 }); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 }); +} + +void SDD1::unload() { +} + +void SDD1::power() { + reset(); +} + +void SDD1::reset() { + sdd1_enable = 0x00; + xfer_enable = 0x00; + dma_ready = false; + + mmc[0] = 0 << 20; + mmc[1] = 1 << 20; + mmc[2] = 2 << 20; + mmc[3] = 3 << 20; + + for(unsigned i = 0; i < 8; i++) { + dma[i].addr = 0; + dma[i].size = 0; + } +} + +uint8 SDD1::mmio_read(unsigned addr) { + addr &= 0xffff; + + if((addr & 0x4380) == 0x4300) { + return cpu.mmio_read(addr); + } + + switch(addr) { + case 0x4804: return mmc[0] >> 20; + case 0x4805: return mmc[1] >> 20; + case 0x4806: return mmc[2] >> 20; + case 0x4807: return mmc[3] >> 20; + } + + return cpu.regs.mdr; +} + +void SDD1::mmio_write(unsigned addr, uint8 data) { + addr &= 0xffff; + + if((addr & 0x4380) == 0x4300) { + unsigned channel = (addr >> 4) & 7; + switch(addr & 15) { + case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break; + case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break; + case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break; + + case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break; + case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break; + } + return cpu.mmio_write(addr, data); + } + + switch(addr) { + case 0x4800: sdd1_enable = data; break; + case 0x4801: xfer_enable = data; break; + + case 0x4804: mmc[0] = data << 20; break; + case 0x4805: mmc[1] = data << 20; break; + case 0x4806: mmc[2] = data << 20; break; + case 0x4807: mmc[3] = data << 20; break; + } +} + +uint8 SDD1::rom_read(unsigned addr) { + return cartridge.rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff)); +} + +//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff +//the design is meant to be as close to the hardware design as possible, thus this code +//avoids adding S-DD1 hooks inside S-CPU::DMA emulation. +// +//the real S-DD1 cannot see $420b (DMA enable) writes, as they are not placed on the bus. +//however, $43x0-$43xf writes (DMAx channel settings) most likely do appear on the bus. +//the S-DD1 also requires fixed addresses for transfers, which wouldn't be necessary if +//it could see $420b writes (eg it would know when the transfer should begin.) +// +//the hardware needs a way to distinguish program code after $4801 writes from DMA +//decompression that follows soon after. +// +//the only plausible design for hardware would be for the S-DD1 to spy on DMAx settings, +//and begin spooling decompression on writes to $4801 that activate a channel. after that, +//it feeds decompressed data only when the ROM read address matches the DMA channel address. +// +//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to +//one transfer per $420b write (for spooling purposes). however, this is not known for certain. +uint8 SDD1::mcu_read(unsigned addr) { + if(sdd1_enable & xfer_enable) { + //at least one channel has S-DD1 decompression enabled ... + for(unsigned i = 0; i < 8; i++) { + if(sdd1_enable & xfer_enable & (1 << i)) { + //S-DD1 always uses fixed transfer mode, so address will not change during transfer + if(addr == dma[i].addr) { + if(!dma_ready) { + //prepare streaming decompression + decomp.init(addr); + dma_ready = true; + } + + //fetch a decompressed byte; once finished, disable channel and invalidate buffer + uint8 data = decomp.read(); + if(--dma[i].size == 0) { + dma_ready = false; + xfer_enable &= ~(1 << i); + } + + return data; + } //address matched + } //channel enabled + } //channel loop + } //S-DD1 decompressor enabled + + //S-DD1 decompression mode inactive; return ROM data + return cartridge.rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff)); +} + +void SDD1::mcu_write(unsigned addr, uint8 data) { +} + +SDD1::SDD1() { +} + +SDD1::~SDD1() { +} + +} diff --git a/snes/chip/sdd1/sdd1.hpp b/snes/chip/sdd1/sdd1.hpp new file mode 100755 index 00000000..b0af2ac4 --- /dev/null +++ b/snes/chip/sdd1/sdd1.hpp @@ -0,0 +1,36 @@ +class SDD1 { +public: + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + + uint8 rom_read(unsigned addr); + uint8 mcu_read(unsigned addr); + void mcu_write(unsigned addr, uint8 data); + + void serialize(serializer&); + SDD1(); + ~SDD1(); + +private: + uint8 sdd1_enable; //channel bit-mask + uint8 xfer_enable; //channel bit-mask + bool dma_ready; //used to initialize decompression module + unsigned mmc[4]; //memory map controller ROM indices + + struct { + unsigned addr; //$43x2-$43x4 -- DMA transfer address + uint16 size; //$43x5-$43x6 -- DMA transfer size + } dma[8]; + +public: + #include "decomp.hpp" + Decomp decomp; +}; + +extern SDD1 sdd1; diff --git a/snes/chip/sdd1/serialization.cpp b/snes/chip/sdd1/serialization.cpp new file mode 100755 index 00000000..1741e1a4 --- /dev/null +++ b/snes/chip/sdd1/serialization.cpp @@ -0,0 +1,15 @@ +#ifdef SDD1_CPP + +void SDD1::serialize(serializer &s) { + s.integer(sdd1_enable); + s.integer(xfer_enable); + s.integer(dma_ready); + s.array(mmc); + + for(unsigned n = 0; n < 8; n++) { + s.integer(dma[n].addr); + s.integer(dma[n].size); + } +} + +#endif diff --git a/snes/chip/spc7110/decomp.cpp b/snes/chip/spc7110/decomp.cpp new file mode 100755 index 00000000..d6b4cce5 --- /dev/null +++ b/snes/chip/spc7110/decomp.cpp @@ -0,0 +1,498 @@ +#ifdef SPC7110_CPP + +uint8 SPC7110::Decomp::read() { + if(decomp_buffer_length == 0) { + //decompress at least (decomp_buffer_size / 2) bytes to the buffer + switch(decomp_mode) { + case 0: mode0(false); break; + case 1: mode1(false); break; + case 2: mode2(false); break; + default: return 0x00; + } + } + + uint8 data = decomp_buffer[decomp_buffer_rdoffset++]; + decomp_buffer_rdoffset &= decomp_buffer_size - 1; + decomp_buffer_length--; + return data; +} + +void SPC7110::Decomp::write(uint8 data) { + decomp_buffer[decomp_buffer_wroffset++] = data; + decomp_buffer_wroffset &= decomp_buffer_size - 1; + decomp_buffer_length++; +} + +uint8 SPC7110::Decomp::dataread() { + unsigned size = cartridge.rom.size() - spc7110.data_rom_offset; + while(decomp_offset >= size) decomp_offset -= size; + return cartridge.rom.read(spc7110.data_rom_offset + decomp_offset++); +} + +void SPC7110::Decomp::init(unsigned mode, unsigned offset, unsigned index) { + decomp_mode = mode; + decomp_offset = offset; + + decomp_buffer_rdoffset = 0; + decomp_buffer_wroffset = 0; + decomp_buffer_length = 0; + + //reset context states + for(unsigned i = 0; i < 32; i++) { + context[i].index = 0; + context[i].invert = 0; + } + + switch(decomp_mode) { + case 0: mode0(true); break; + case 1: mode1(true); break; + case 2: mode2(true); break; + } + + //decompress up to requested output data index + while(index--) read(); +} + +// + +void SPC7110::Decomp::mode0(bool init) { + static uint8 val, in, span; + static int out, inverts, lps, in_count; + + if(init == true) { + out = inverts = lps = 0; + span = 0xff; + val = dataread(); + in = dataread(); + in_count = 8; + return; + } + + while(decomp_buffer_length < (decomp_buffer_size >> 1)) { + for(unsigned bit = 0; bit < 8; bit++) { + //get context + uint8 mask = (1 << (bit & 3)) - 1; + uint8 con = mask + ((inverts & mask) ^ (lps & mask)); + if(bit > 3) con += 15; + + //get prob and mps + unsigned prob = probability(con); + unsigned mps = (((out >> 15) & 1) ^ context[con].invert); + + //get bit + unsigned flag_lps; + if(val <= span - prob) { //mps + span = span - prob; + out = (out << 1) + mps; + flag_lps = 0; + } else { //lps + val = val - (span - (prob - 1)); + span = prob - 1; + out = (out << 1) + 1 - mps; + flag_lps = 1; + } + + //renormalize + unsigned shift = 0; + while(span < 0x7f) { + shift++; + + span = (span << 1) + 1; + val = (val << 1) + (in >> 7); + + in <<= 1; + if(--in_count == 0) { + in = dataread(); + in_count = 8; + } + } + + //update processing info + lps = (lps << 1) + flag_lps; + inverts = (inverts << 1) + context[con].invert; + + //update context state + if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; + if(flag_lps) context[con].index = next_lps(con); + else if(shift) context[con].index = next_mps(con); + } + + //save byte + write(out); + } +} + +void SPC7110::Decomp::mode1(bool init) { + static int pixelorder[4], realorder[4]; + static uint8 in, val, span; + static int out, inverts, lps, in_count; + + if(init == true) { + for(unsigned i = 0; i < 4; i++) pixelorder[i] = i; + out = inverts = lps = 0; + span = 0xff; + val = dataread(); + in = dataread(); + in_count = 8; + return; + } + + while(decomp_buffer_length < (decomp_buffer_size >> 1)) { + for(unsigned pixel = 0; pixel < 8; pixel++) { + //get first symbol context + unsigned a = ((out >> (1 * 2)) & 3); + unsigned b = ((out >> (7 * 2)) & 3); + unsigned c = ((out >> (8 * 2)) & 3); + unsigned con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); + + //update pixel order + unsigned m, n; + for(m = 0; m < 4; m++) if(pixelorder[m] == a) break; + for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1]; + pixelorder[0] = a; + + //calculate the real pixel order + for(m = 0; m < 4; m++) realorder[m] = pixelorder[m]; + + //rotate reference pixel c value to top + for(m = 0; m < 4; m++) if(realorder[m] == c) break; + for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; + realorder[0] = c; + + //rotate reference pixel b value to top + for(m = 0; m < 4; m++) if(realorder[m] == b) break; + for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; + realorder[0] = b; + + //rotate reference pixel a value to top + for(m = 0; m < 4; m++) if(realorder[m] == a) break; + for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; + realorder[0] = a; + + //get 2 symbols + for(unsigned bit = 0; bit < 2; bit++) { + //get prob + unsigned prob = probability(con); + + //get symbol + unsigned flag_lps; + if(val <= span - prob) { //mps + span = span - prob; + flag_lps = 0; + } else { //lps + val = val - (span - (prob - 1)); + span = prob - 1; + flag_lps = 1; + } + + //renormalize + unsigned shift = 0; + while(span < 0x7f) { + shift++; + + span = (span << 1) + 1; + val = (val << 1) + (in >> 7); + + in <<= 1; + if(--in_count == 0) { + in = dataread(); + in_count = 8; + } + } + + //update processing info + lps = (lps << 1) + flag_lps; + inverts = (inverts << 1) + context[con].invert; + + //update context state + if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; + if(flag_lps) context[con].index = next_lps(con); + else if(shift) context[con].index = next_mps(con); + + //get next context + con = 5 + (con << 1) + ((lps ^ inverts) & 1); + } + + //get pixel + b = realorder[(lps ^ inverts) & 3]; + out = (out << 2) + b; + } + + //turn pixel data into bitplanes + unsigned data = deinterleave_2x8(out); + write(data >> 8); + write(data >> 0); + } +} + +void SPC7110::Decomp::mode2(bool init) { + static int pixelorder[16], realorder[16]; + static uint8 bitplanebuffer[16], buffer_index; + static uint8 in, val, span; + static int out0, out1, inverts, lps, in_count; + + if(init == true) { + for(unsigned i = 0; i < 16; i++) pixelorder[i] = i; + buffer_index = 0; + out0 = out1 = inverts = lps = 0; + span = 0xff; + val = dataread(); + in = dataread(); + in_count = 8; + return; + } + + while(decomp_buffer_length < (decomp_buffer_size >> 1)) { + for(unsigned pixel = 0; pixel < 8; pixel++) { + //get first symbol context + unsigned a = ((out0 >> (0 * 4)) & 15); + unsigned b = ((out0 >> (7 * 4)) & 15); + unsigned c = ((out1 >> (0 * 4)) & 15); + unsigned con = 0; + unsigned refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); + + //update pixel order + unsigned m, n; + for(m = 0; m < 16; m++) if(pixelorder[m] == a) break; + for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1]; + pixelorder[0] = a; + + //calculate the real pixel order + for(m = 0; m < 16; m++) realorder[m] = pixelorder[m]; + + //rotate reference pixel c value to top + for(m = 0; m < 16; m++) if(realorder[m] == c) break; + for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; + realorder[0] = c; + + //rotate reference pixel b value to top + for(m = 0; m < 16; m++) if(realorder[m] == b) break; + for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; + realorder[0] = b; + + //rotate reference pixel a value to top + for(m = 0; m < 16; m++) if(realorder[m] == a) break; + for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; + realorder[0] = a; + + //get 4 symbols + for(unsigned bit = 0; bit < 4; bit++) { + //get prob + unsigned prob = probability(con); + + //get symbol + unsigned flag_lps; + if(val <= span - prob) { //mps + span = span - prob; + flag_lps = 0; + } else { //lps + val = val - (span - (prob - 1)); + span = prob - 1; + flag_lps = 1; + } + + //renormalize + unsigned shift = 0; + while(span < 0x7f) { + shift++; + + span = (span << 1) + 1; + val = (val << 1) + (in >> 7); + + in <<= 1; + if(--in_count == 0) { + in = dataread(); + in_count = 8; + } + } + + //update processing info + lps = (lps << 1) + flag_lps; + unsigned invertbit = context[con].invert; + inverts = (inverts << 1) + invertbit; + + //update context state + if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; + if(flag_lps) context[con].index = next_lps(con); + else if(shift) context[con].index = next_mps(con); + + //get next context + con = mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); + } + + //get pixel + b = realorder[(lps ^ inverts) & 0x0f]; + out1 = (out1 << 4) + ((out0 >> 28) & 0x0f); + out0 = (out0 << 4) + b; + } + + //convert pixel data into bitplanes + unsigned data = deinterleave_4x8(out0); + write(data >> 24); + write(data >> 16); + bitplanebuffer[buffer_index++] = data >> 8; + bitplanebuffer[buffer_index++] = data >> 0; + + if(buffer_index == 16) { + for(unsigned i = 0; i < 16; i++) write(bitplanebuffer[i]); + buffer_index = 0; + } + } +} + +// + +const uint8 SPC7110::Decomp::evolution_table[53][4] = { +//{ prob, nextlps, nextmps, toggle invert }, + + { 0x5a, 1, 1, 1 }, + { 0x25, 6, 2, 0 }, + { 0x11, 8, 3, 0 }, + { 0x08, 10, 4, 0 }, + { 0x03, 12, 5, 0 }, + { 0x01, 15, 5, 0 }, + + { 0x5a, 7, 7, 1 }, + { 0x3f, 19, 8, 0 }, + { 0x2c, 21, 9, 0 }, + { 0x20, 22, 10, 0 }, + { 0x17, 23, 11, 0 }, + { 0x11, 25, 12, 0 }, + { 0x0c, 26, 13, 0 }, + { 0x09, 28, 14, 0 }, + { 0x07, 29, 15, 0 }, + { 0x05, 31, 16, 0 }, + { 0x04, 32, 17, 0 }, + { 0x03, 34, 18, 0 }, + { 0x02, 35, 5, 0 }, + + { 0x5a, 20, 20, 1 }, + { 0x48, 39, 21, 0 }, + { 0x3a, 40, 22, 0 }, + { 0x2e, 42, 23, 0 }, + { 0x26, 44, 24, 0 }, + { 0x1f, 45, 25, 0 }, + { 0x19, 46, 26, 0 }, + { 0x15, 25, 27, 0 }, + { 0x11, 26, 28, 0 }, + { 0x0e, 26, 29, 0 }, + { 0x0b, 27, 30, 0 }, + { 0x09, 28, 31, 0 }, + { 0x08, 29, 32, 0 }, + { 0x07, 30, 33, 0 }, + { 0x05, 31, 34, 0 }, + { 0x04, 33, 35, 0 }, + { 0x04, 33, 36, 0 }, + { 0x03, 34, 37, 0 }, + { 0x02, 35, 38, 0 }, + { 0x02, 36, 5, 0 }, + + { 0x58, 39, 40, 1 }, + { 0x4d, 47, 41, 0 }, + { 0x43, 48, 42, 0 }, + { 0x3b, 49, 43, 0 }, + { 0x34, 50, 44, 0 }, + { 0x2e, 51, 45, 0 }, + { 0x29, 44, 46, 0 }, + { 0x25, 45, 24, 0 }, + + { 0x56, 47, 48, 1 }, + { 0x4f, 47, 49, 0 }, + { 0x47, 48, 50, 0 }, + { 0x41, 49, 51, 0 }, + { 0x3c, 50, 52, 0 }, + { 0x37, 51, 43, 0 }, +}; + +const uint8 SPC7110::Decomp::mode2_context_table[32][2] = { +//{ next 0, next 1 }, + + { 1, 2 }, + + { 3, 8 }, + { 13, 14 }, + + { 15, 16 }, + { 17, 18 }, + { 19, 20 }, + { 21, 22 }, + { 23, 24 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 27, 28 }, + { 29, 30 }, + + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + + { 31, 31 }, +}; + +uint8 SPC7110::Decomp::probability (unsigned n) { return evolution_table[context[n].index][0]; } +uint8 SPC7110::Decomp::next_lps (unsigned n) { return evolution_table[context[n].index][1]; } +uint8 SPC7110::Decomp::next_mps (unsigned n) { return evolution_table[context[n].index][2]; } +bool SPC7110::Decomp::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; } + +unsigned SPC7110::Decomp::deinterleave_2x8(unsigned data) { + //reverse morton lookup: de-interleave two 8-bit values + //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8 + //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0 + unsigned result = 0; + for(unsigned mask = 1u << 15; mask; mask >>= 2) result = (result << 1) | (bool)(data & mask); + for(unsigned mask = 1u << 14; mask; mask >>= 2) result = (result << 1) | (bool)(data & mask); + return result; +} + +unsigned SPC7110::Decomp::deinterleave_4x8(unsigned data) { + //reverse morton lookup: de-interleave four 8-bit values + //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24 + //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16 + //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8 + //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0 + unsigned result = 0; + for(unsigned mask = 1u << 31; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask); + for(unsigned mask = 1u << 30; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask); + for(unsigned mask = 1u << 29; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask); + for(unsigned mask = 1u << 28; mask; mask >>= 4) result = (result << 1) | (bool)(data & mask); + return result; +} + +// + +void SPC7110::Decomp::reset() { + //mode 3 is invalid; this is treated as a special case to always return 0x00 + //set to mode 3 so that reading decomp port before starting first decomp will return 0x00 + decomp_mode = 3; + + decomp_buffer_rdoffset = 0; + decomp_buffer_wroffset = 0; + decomp_buffer_length = 0; +} + +SPC7110::Decomp::Decomp() { + decomp_buffer = new uint8_t[decomp_buffer_size]; + reset(); +} + +SPC7110::Decomp::~Decomp() { + delete[] decomp_buffer; +} + +#endif diff --git a/snes/chip/spc7110/decomp.hpp b/snes/chip/spc7110/decomp.hpp new file mode 100755 index 00000000..c11c6ad4 --- /dev/null +++ b/snes/chip/spc7110/decomp.hpp @@ -0,0 +1,44 @@ +class Decomp { +public: + uint8 read(); + void init(unsigned mode, unsigned offset, unsigned index); + void reset(); + + void serialize(serializer&); + Decomp(); + ~Decomp(); + +private: + unsigned decomp_mode; + unsigned decomp_offset; + + //read() will spool chunks half the size of decomp_buffer_size + enum { decomp_buffer_size = 64 }; //must be >= 64, and must be a power of two + uint8 *decomp_buffer; + unsigned decomp_buffer_rdoffset; + unsigned decomp_buffer_wroffset; + unsigned decomp_buffer_length; + + void write(uint8 data); + uint8 dataread(); + + void mode0(bool init); + void mode1(bool init); + void mode2(bool init); + + static const uint8 evolution_table[53][4]; + static const uint8 mode2_context_table[32][2]; + + struct ContextState { + uint8 index; + uint8 invert; + } context[32]; + + uint8 probability(unsigned n); + uint8 next_lps(unsigned n); + uint8 next_mps(unsigned n); + bool toggle_invert(unsigned n); + + unsigned deinterleave_2x8(unsigned data); + unsigned deinterleave_4x8(unsigned data); +}; diff --git a/snes/chip/spc7110/serialization.cpp b/snes/chip/spc7110/serialization.cpp new file mode 100755 index 00000000..196d04c0 --- /dev/null +++ b/snes/chip/spc7110/serialization.cpp @@ -0,0 +1,82 @@ +#ifdef SPC7110_CPP + +void SPC7110::Decomp::serialize(serializer &s) { + s.integer(decomp_mode); + s.integer(decomp_offset); + + s.array(decomp_buffer, decomp_buffer_size); + s.integer(decomp_buffer_rdoffset); + s.integer(decomp_buffer_wroffset); + s.integer(decomp_buffer_length); + + for(unsigned n = 0; n < 32; n++) { + s.integer(context[n].index); + s.integer(context[n].invert); + } +} + +void SPC7110::serialize(serializer &s) { + s.integer(r4801); + s.integer(r4802); + s.integer(r4803); + s.integer(r4804); + s.integer(r4805); + s.integer(r4806); + s.integer(r4807); + s.integer(r4808); + s.integer(r4809); + s.integer(r480a); + s.integer(r480b); + s.integer(r480c); + decomp.serialize(s); + + s.integer(r4811); + s.integer(r4812); + s.integer(r4813); + s.integer(r4814); + s.integer(r4815); + s.integer(r4816); + s.integer(r4817); + s.integer(r4818); + s.integer(r481x); + s.integer(r4814_latch); + s.integer(r4815_latch); + + s.integer(r4820); + s.integer(r4821); + s.integer(r4822); + s.integer(r4823); + s.integer(r4824); + s.integer(r4825); + s.integer(r4826); + s.integer(r4827); + s.integer(r4828); + s.integer(r4829); + s.integer(r482a); + s.integer(r482b); + s.integer(r482c); + s.integer(r482d); + s.integer(r482e); + s.integer(r482f); + + s.integer(r4830); + s.integer(r4831); + s.integer(r4832); + s.integer(r4833); + s.integer(r4834); + + s.integer(dx_offset); + s.integer(ex_offset); + s.integer(fx_offset); + + s.integer(r4840); + s.integer(r4841); + s.integer(r4842); + + s.array(rtc); + s.integer(rtc_state); + s.integer(rtc_mode); + s.integer(rtc_index); +} + +#endif diff --git a/snes/chip/spc7110/spc7110.cpp b/snes/chip/spc7110/spc7110.cpp new file mode 100755 index 00000000..835ddbb6 --- /dev/null +++ b/snes/chip/spc7110/spc7110.cpp @@ -0,0 +1,675 @@ +#include + +#define SPC7110_CPP +namespace SNES { + +SPC7110 spc7110; + +#include "serialization.cpp" +#include "decomp.cpp" + +const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +void SPC7110::init() { +} + +void SPC7110::load() { + for(unsigned n = 0; n < 20; n++) rtc[n] = 0xff; + if(cartridge.has_spc7110rtc()) cartridge.nvram.append({ ".rtc", rtc, 20 }); +} + +void SPC7110::unload() { +} + +void SPC7110::power() { + reset(); +} + +void SPC7110::reset() { + r4801 = 0x00; + r4802 = 0x00; + r4803 = 0x00; + r4804 = 0x00; + r4805 = 0x00; + r4806 = 0x00; + r4807 = 0x00; + r4808 = 0x00; + r4809 = 0x00; + r480a = 0x00; + r480b = 0x00; + r480c = 0x00; + + decomp.reset(); + + r4811 = 0x00; + r4812 = 0x00; + r4813 = 0x00; + r4814 = 0x00; + r4815 = 0x00; + r4816 = 0x00; + r4817 = 0x00; + r4818 = 0x00; + + r481x = 0x00; + r4814_latch = false; + r4815_latch = false; + + r4820 = 0x00; + r4821 = 0x00; + r4822 = 0x00; + r4823 = 0x00; + r4824 = 0x00; + r4825 = 0x00; + r4826 = 0x00; + r4827 = 0x00; + r4828 = 0x00; + r4829 = 0x00; + r482a = 0x00; + r482b = 0x00; + r482c = 0x00; + r482d = 0x00; + r482e = 0x00; + r482f = 0x00; + + r4830 = 0x00; + mmio_write(0x4831, 0); + mmio_write(0x4832, 1); + mmio_write(0x4833, 2); + r4834 = 0x00; + + r4840 = 0x00; + r4841 = 0x00; + r4842 = 0x00; + + if(cartridge.has_spc7110rtc()) { + rtc_state = RTCS_Inactive; + rtc_mode = RTCM_Linear; + rtc_index = 0; + } +} + +unsigned SPC7110::datarom_addr(unsigned addr) { + unsigned size = cartridge.rom.size() - data_rom_offset; + while(addr >= size) addr -= size; + return data_rom_offset + addr; +} + +unsigned SPC7110::data_pointer() { return r4811 + (r4812 << 8) + (r4813 << 16); } +unsigned SPC7110::data_adjust() { return r4814 + (r4815 << 8); } +unsigned SPC7110::data_increment() { return r4816 + (r4817 << 8); } +void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; } +void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; } + +void SPC7110::update_time(int offset) { + time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); + time_t current_time = time(0) - offset; + + //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. + //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by + //accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow + //rtc[] timestamp to remain valid for up to ~34 years from the last update, even if + //time_t overflows. calculation should be valid regardless of number representation, time_t size, + //or whether time_t is signed or unsigned. + time_t diff + = (current_time >= rtc_time) + ? (current_time - rtc_time) + : (std::numeric_limits::max() - rtc_time + current_time + 1); //compensate for overflow + if(diff > std::numeric_limits::max() / 2) diff = 0; //compensate for underflow + + bool update = true; + if(rtc[13] & 1) update = false; //do not update if CR0 timer disable flag is set + if(rtc[15] & 3) update = false; //do not update if CR2 timer disable flags are set + + if(diff > 0 && update == true) { + unsigned second = rtc[ 0] + rtc[ 1] * 10; + unsigned minute = rtc[ 2] + rtc[ 3] * 10; + unsigned hour = rtc[ 4] + rtc[ 5] * 10; + unsigned day = rtc[ 6] + rtc[ 7] * 10; + unsigned month = rtc[ 8] + rtc[ 9] * 10; + unsigned year = rtc[10] + rtc[11] * 10; + unsigned weekday = rtc[12]; + + day--; + month--; + year += (year >= 90) ? 1900 : 2000; //range = 1990-2089 + + second += diff; + while(second >= 60) { + second -= 60; + + minute++; + if(minute < 60) continue; + minute = 0; + + hour++; + if(hour < 24) continue; + hour = 0; + + day++; + weekday = (weekday + 1) % 7; + unsigned days = months[month % 12]; + if(days == 28) { + bool leapyear = false; + if((year % 4) == 0) { + leapyear = true; + if((year % 100) == 0 && (year % 400) != 0) leapyear = false; + } + if(leapyear) days++; + } + if(day < days) continue; + day = 0; + + month++; + if(month < 12) continue; + month = 0; + + year++; + } + + day++; + month++; + year %= 100; + + rtc[ 0] = second % 10; + rtc[ 1] = second / 10; + rtc[ 2] = minute % 10; + rtc[ 3] = minute / 10; + rtc[ 4] = hour % 10; + rtc[ 5] = hour / 10; + rtc[ 6] = day % 10; + rtc[ 7] = day / 10; + rtc[ 8] = month % 10; + rtc[ 9] = month / 10; + rtc[10] = year % 10; + rtc[11] = (year / 10) % 10; + rtc[12] = weekday % 7; + } + + rtc[16] = current_time >> 0; + rtc[17] = current_time >> 8; + rtc[18] = current_time >> 16; + rtc[19] = current_time >> 24; +} + +uint8 SPC7110::mmio_read(unsigned addr) { + addr &= 0xffff; + + switch(addr) { + //================== + //decompression unit + //================== + + case 0x4800: { + uint16 counter = (r4809 + (r480a << 8)); + counter--; + r4809 = counter; + r480a = counter >> 8; + return decomp.read(); + } + case 0x4801: return r4801; + case 0x4802: return r4802; + case 0x4803: return r4803; + case 0x4804: return r4804; + case 0x4805: return r4805; + case 0x4806: return r4806; + case 0x4807: return r4807; + case 0x4808: return r4808; + case 0x4809: return r4809; + case 0x480a: return r480a; + case 0x480b: return r480b; + case 0x480c: { + uint8 status = r480c; + r480c &= 0x7f; + return status; + } + + //============== + //data port unit + //============== + + case 0x4810: { + if(r481x != 0x07) return 0x00; + + unsigned addr = data_pointer(); + unsigned adjust = data_adjust(); + if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend + + unsigned adjustaddr = addr; + if(r4818 & 2) { + adjustaddr += adjust; + set_data_adjust(adjust + 1); + } + + uint8 data = cartridge.rom.read(datarom_addr(adjustaddr)); + if(!(r4818 & 2)) { + unsigned increment = (r4818 & 1) ? data_increment() : 1; + if(r4818 & 4) increment = (int16)increment; //16-bit sign extend + + if((r4818 & 16) == 0) { + set_data_pointer(addr + increment); + } else { + set_data_adjust(adjust + increment); + } + } + + return data; + } + case 0x4811: return r4811; + case 0x4812: return r4812; + case 0x4813: return r4813; + case 0x4814: return r4814; + case 0x4815: return r4815; + case 0x4816: return r4816; + case 0x4817: return r4817; + case 0x4818: return r4818; + case 0x481a: { + if(r481x != 0x07) return 0x00; + + unsigned addr = data_pointer(); + unsigned adjust = data_adjust(); + if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend + + uint8 data = cartridge.rom.read(datarom_addr(addr + adjust)); + if((r4818 & 0x60) == 0x60) { + if((r4818 & 16) == 0) { + set_data_pointer(addr + adjust); + } else { + set_data_adjust(adjust + adjust); + } + } + + return data; + } + + //========= + //math unit + //========= + + case 0x4820: return r4820; + case 0x4821: return r4821; + case 0x4822: return r4822; + case 0x4823: return r4823; + case 0x4824: return r4824; + case 0x4825: return r4825; + case 0x4826: return r4826; + case 0x4827: return r4827; + case 0x4828: return r4828; + case 0x4829: return r4829; + case 0x482a: return r482a; + case 0x482b: return r482b; + case 0x482c: return r482c; + case 0x482d: return r482d; + case 0x482e: return r482e; + case 0x482f: { + uint8 status = r482f; + r482f &= 0x7f; + return status; + } + + //=================== + //memory mapping unit + //=================== + + case 0x4830: return r4830; + case 0x4831: return r4831; + case 0x4832: return r4832; + case 0x4833: return r4833; + case 0x4834: return r4834; + + //==================== + //real-time clock unit + //==================== + + case 0x4840: return r4840; + case 0x4841: { + if(rtc_state == RTCS_Inactive || rtc_state == RTCS_ModeSelect) return 0x00; + + r4842 = 0x80; + uint8 data = rtc[rtc_index]; + rtc_index = (rtc_index + 1) & 15; + return data; + } + case 0x4842: { + uint8 status = r4842; + r4842 &= 0x7f; + return status; + } + } + + return cpu.regs.mdr; +} + +void SPC7110::mmio_write(unsigned addr, uint8 data) { + addr &= 0xffff; + + switch(addr) { + //================== + //decompression unit + //================== + + case 0x4801: r4801 = data; break; + case 0x4802: r4802 = data; break; + case 0x4803: r4803 = data; break; + case 0x4804: r4804 = data; break; + case 0x4805: r4805 = data; break; + case 0x4806: { + r4806 = data; + + unsigned table = (r4801 + (r4802 << 8) + (r4803 << 16)); + unsigned index = (r4804 << 2); + unsigned length = (r4809 + (r480a << 8)); + unsigned addr = datarom_addr(table + index); + unsigned mode = (cartridge.rom.read(addr + 0)); + unsigned offset = (cartridge.rom.read(addr + 1) << 16) + + (cartridge.rom.read(addr + 2) << 8) + + (cartridge.rom.read(addr + 3) << 0); + + decomp.init(mode, offset, (r4805 + (r4806 << 8)) << mode); + r480c = 0x80; + } break; + + case 0x4807: r4807 = data; break; + case 0x4808: r4808 = data; break; + case 0x4809: r4809 = data; break; + case 0x480a: r480a = data; break; + case 0x480b: r480b = data; break; + + //============== + //data port unit + //============== + + case 0x4811: r4811 = data; r481x |= 0x01; break; + case 0x4812: r4812 = data; r481x |= 0x02; break; + case 0x4813: r4813 = data; r481x |= 0x04; break; + case 0x4814: { + r4814 = data; + r4814_latch = true; + if(!r4815_latch) break; + if(!(r4818 & 2)) break; + if(r4818 & 0x10) break; + + if((r4818 & 0x60) == 0x20) { + unsigned increment = data_adjust() & 0xff; + if(r4818 & 8) increment = (int8)increment; //8-bit sign extend + set_data_pointer(data_pointer() + increment); + } else if((r4818 & 0x60) == 0x40) { + unsigned increment = data_adjust(); + if(r4818 & 8) increment = (int16)increment; //16-bit sign extend + set_data_pointer(data_pointer() + increment); + } + } break; + case 0x4815: { + r4815 = data; + r4815_latch = true; + if(!r4814_latch) break; + if(!(r4818 & 2)) break; + if(r4818 & 0x10) break; + + if((r4818 & 0x60) == 0x20) { + unsigned increment = data_adjust() & 0xff; + if(r4818 & 8) increment = (int8)increment; //8-bit sign extend + set_data_pointer(data_pointer() + increment); + } else if((r4818 & 0x60) == 0x40) { + unsigned increment = data_adjust(); + if(r4818 & 8) increment = (int16)increment; //16-bit sign extend + set_data_pointer(data_pointer() + increment); + } + } break; + case 0x4816: r4816 = data; break; + case 0x4817: r4817 = data; break; + case 0x4818: { + if(r481x != 0x07) break; + + r4818 = data; + r4814_latch = r4815_latch = false; + } break; + + //========= + //math unit + //========= + + case 0x4820: r4820 = data; break; + case 0x4821: r4821 = data; break; + case 0x4822: r4822 = data; break; + case 0x4823: r4823 = data; break; + case 0x4824: r4824 = data; break; + case 0x4825: { + r4825 = data; + + if(r482e & 1) { + //signed 16-bit x 16-bit multiplication + int16 r0 = (int16)(r4824 + (r4825 << 8)); + int16 r1 = (int16)(r4820 + (r4821 << 8)); + + signed result = r0 * r1; + r4828 = result; + r4829 = result >> 8; + r482a = result >> 16; + r482b = result >> 24; + } else { + //unsigned 16-bit x 16-bit multiplication + uint16 r0 = (uint16)(r4824 + (r4825 << 8)); + uint16 r1 = (uint16)(r4820 + (r4821 << 8)); + + unsigned result = r0 * r1; + r4828 = result; + r4829 = result >> 8; + r482a = result >> 16; + r482b = result >> 24; + } + + r482f = 0x80; + } break; + case 0x4826: r4826 = data; break; + case 0x4827: { + r4827 = data; + + if(r482e & 1) { + //signed 32-bit x 16-bit division + int32 dividend = (int32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24)); + int16 divisor = (int16)(r4826 + (r4827 << 8)); + + int32 quotient; + int16 remainder; + + if(divisor) { + quotient = (int32)(dividend / divisor); + remainder = (int32)(dividend % divisor); + } else { + //illegal division by zero + quotient = 0; + remainder = dividend & 0xffff; + } + + r4828 = quotient; + r4829 = quotient >> 8; + r482a = quotient >> 16; + r482b = quotient >> 24; + + r482c = remainder; + r482d = remainder >> 8; + } else { + //unsigned 32-bit x 16-bit division + uint32 dividend = (uint32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24)); + uint16 divisor = (uint16)(r4826 + (r4827 << 8)); + + uint32 quotient; + uint16 remainder; + + if(divisor) { + quotient = (uint32)(dividend / divisor); + remainder = (uint16)(dividend % divisor); + } else { + //illegal division by zero + quotient = 0; + remainder = dividend & 0xffff; + } + + r4828 = quotient; + r4829 = quotient >> 8; + r482a = quotient >> 16; + r482b = quotient >> 24; + + r482c = remainder; + r482d = remainder >> 8; + } + + r482f = 0x80; + } break; + + case 0x482e: { + //reset math unit + r4820 = r4821 = r4822 = r4823 = 0; + r4824 = r4825 = r4826 = r4827 = 0; + r4828 = r4829 = r482a = r482b = 0; + r482c = r482d = 0; + + r482e = data; + } break; + + //=================== + //memory mapping unit + //=================== + + case 0x4830: r4830 = data; break; + + case 0x4831: { + r4831 = data; + dx_offset = datarom_addr(data * 0x100000); + } break; + + case 0x4832: { + r4832 = data; + ex_offset = datarom_addr(data * 0x100000); + } break; + + case 0x4833: { + r4833 = data; + fx_offset = datarom_addr(data * 0x100000); + } break; + + case 0x4834: r4834 = data; break; + + //==================== + //real-time clock unit + //==================== + + case 0x4840: { + r4840 = data; + if(!(r4840 & 1)) { + //disable RTC + rtc_state = RTCS_Inactive; + update_time(); + } else { + //enable RTC + r4842 = 0x80; + rtc_state = RTCS_ModeSelect; + } + } break; + + case 0x4841: { + r4841 = data; + + switch(rtc_state) { + case RTCS_ModeSelect: { + if(data == RTCM_Linear || data == RTCM_Indexed) { + r4842 = 0x80; + rtc_state = RTCS_IndexSelect; + rtc_mode = (RTC_Mode)data; + rtc_index = 0; + } + } break; + + case RTCS_IndexSelect: { + r4842 = 0x80; + rtc_index = data & 15; + if(rtc_mode == RTCM_Linear) rtc_state = RTCS_Write; + } break; + + case RTCS_Write: { + r4842 = 0x80; + + //control register 0 + if(rtc_index == 13) { + //increment second counter + if(data & 2) update_time(+1); + + //round minute counter + if(data & 8) { + update_time(); + + unsigned second = rtc[ 0] + rtc[ 1] * 10; + //clear seconds + rtc[0] = 0; + rtc[1] = 0; + + if(second >= 30) update_time(+60); + } + } + + //control register 2 + if(rtc_index == 15) { + //disable timer and clear second counter + if((data & 1) && !(rtc[15] & 1)) { + update_time(); + + //clear seconds + rtc[0] = 0; + rtc[1] = 0; + } + + //disable timer + if((data & 2) && !(rtc[15] & 2)) { + update_time(); + } + } + + rtc[rtc_index] = data & 15; + rtc_index = (rtc_index + 1) & 15; + } break; + } //switch(rtc_state) + } break; + } +} + +SPC7110::SPC7110() { +} + +//============ +//SPC7110::MCU +//============ + +uint8 SPC7110::mcu_read(unsigned addr) { + if(addr <= 0xdfffff) return cartridge.rom.read(dx_offset + (addr & 0x0fffff)); + if(addr <= 0xefffff) return cartridge.rom.read(ex_offset + (addr & 0x0fffff)); + if(addr <= 0xffffff) return cartridge.rom.read(fx_offset + (addr & 0x0fffff)); + return cpu.regs.mdr; +} + +void SPC7110::mcu_write(unsigned addr, uint8 data) { +} + +//============ +//SPC7110::DCU +//============ + +uint8 SPC7110::dcu_read(unsigned) { + return mmio_read(0x4800); +} + +void SPC7110::dcu_write(unsigned, uint8) { +} + +//============ +//SPC7110::RAM +//============ + +uint8 SPC7110::ram_read(unsigned addr) { + return cartridge.ram.read(addr & 0x1fff); +} + +void SPC7110::ram_write(unsigned addr, uint8 data) { + if(r4830 & 0x80) cartridge.ram.write(addr & 0x1fff, data); +} + +} diff --git a/snes/chip/spc7110/spc7110.hpp b/snes/chip/spc7110/spc7110.hpp new file mode 100755 index 00000000..003c4237 --- /dev/null +++ b/snes/chip/spc7110/spc7110.hpp @@ -0,0 +1,131 @@ +//SPC7110 emulator - version 0.05 (2011-06-27) +//Copyright (c) 2008-2011, byuu and neviksti + +class SPC7110 { +public: + uint8 rtc[20]; + unsigned data_rom_offset; + + void init(); + void load(); + void unload(); + void power(); + void reset(); + + unsigned datarom_addr(unsigned addr); + + unsigned data_pointer(); + unsigned data_adjust(); + unsigned data_increment(); + void set_data_pointer(unsigned addr); + void set_data_adjust(unsigned addr); + + void update_time(int offset = 0); + time_t create_time(); + + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + + uint8 mcu_read(unsigned addr); + void mcu_write(unsigned addr, uint8 data); + + uint8 dcu_read(unsigned); + void dcu_write(unsigned, uint8); + + uint8 ram_read(unsigned addr); + void ram_write(unsigned addr, uint8 data); + + //spc7110decomp + void decomp_init(); + uint8 decomp_read(); + + void serialize(serializer&); + SPC7110(); + +private: + //================== + //decompression unit + //================== + uint8 r4801; //compression table low + uint8 r4802; //compression table high + uint8 r4803; //compression table bank + uint8 r4804; //compression table index + uint8 r4805; //decompression buffer index low + uint8 r4806; //decompression buffer index high + uint8 r4807; //??? + uint8 r4808; //??? + uint8 r4809; //compression length low + uint8 r480a; //compression length high + uint8 r480b; //decompression control register + uint8 r480c; //decompression status + + #include "decomp.hpp" + Decomp decomp; + + //============== + //data port unit + //============== + uint8 r4811; //data pointer low + uint8 r4812; //data pointer high + uint8 r4813; //data pointer bank + uint8 r4814; //data adjust low + uint8 r4815; //data adjust high + uint8 r4816; //data increment low + uint8 r4817; //data increment high + uint8 r4818; //data port control register + + uint8 r481x; + + bool r4814_latch; + bool r4815_latch; + + //========= + //math unit + //========= + uint8 r4820; //16-bit multiplicand B0, 32-bit dividend B0 + uint8 r4821; //16-bit multiplicand B1, 32-bit dividend B1 + uint8 r4822; //32-bit dividend B2 + uint8 r4823; //32-bit dividend B3 + uint8 r4824; //16-bit multiplier B0 + uint8 r4825; //16-bit multiplier B1 + uint8 r4826; //16-bit divisor B0 + uint8 r4827; //16-bit divisor B1 + uint8 r4828; //32-bit product B0, 32-bit quotient B0 + uint8 r4829; //32-bit product B1, 32-bit quotient B1 + uint8 r482a; //32-bit product B2, 32-bit quotient B2 + uint8 r482b; //32-bit product B3, 32-bit quotient B3 + uint8 r482c; //16-bit remainder B0 + uint8 r482d; //16-bit remainder B1 + uint8 r482e; //math control register + uint8 r482f; //math status + + //=================== + //memory mapping unit + //=================== + uint8 r4830; //SRAM write enable + uint8 r4831; //$[d0-df]:[0000-ffff] mapping + uint8 r4832; //$[e0-ef]:[0000-ffff] mapping + uint8 r4833; //$[f0-ff]:[0000-ffff] mapping + uint8 r4834; //??? + + unsigned dx_offset; + unsigned ex_offset; + unsigned fx_offset; + + //==================== + //real-time clock unit + //==================== + uint8 r4840; //RTC latch + uint8 r4841; //RTC index/data port + uint8 r4842; //RTC status + + enum RTC_State { RTCS_Inactive, RTCS_ModeSelect, RTCS_IndexSelect, RTCS_Write }; + enum RTC_Mode { RTCM_Linear = 0x03, RTCM_Indexed = 0x0c }; + unsigned rtc_state; + unsigned rtc_mode; + unsigned rtc_index; + + static const unsigned months[12]; +}; + +extern SPC7110 spc7110; diff --git a/snes/chip/srtc/serialization.cpp b/snes/chip/srtc/serialization.cpp new file mode 100755 index 00000000..4614112a --- /dev/null +++ b/snes/chip/srtc/serialization.cpp @@ -0,0 +1,9 @@ +#ifdef SRTC_CPP + +void SRTC::serialize(serializer &s) { + s.array(rtc); + s.integer(rtc_mode); + s.integer(rtc_index); +} + +#endif diff --git a/snes/chip/srtc/srtc.cpp b/snes/chip/srtc/srtc.cpp new file mode 100755 index 00000000..1dd8f86e --- /dev/null +++ b/snes/chip/srtc/srtc.cpp @@ -0,0 +1,232 @@ +#include + +#define SRTC_CPP +namespace SNES { + +SRTC srtc; + +#include "serialization.cpp" + +const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +void SRTC::init() { +} + +void SRTC::load() { + for(unsigned n = 0; n < 20; n++) rtc[n] = 0xff; + cartridge.nvram.append({ ".rtc", rtc, 20 }); +} + +void SRTC::unload() { +} + +void SRTC::power() { + reset(); +} + +void SRTC::reset() { + rtc_mode = RtcRead; + rtc_index = -1; + update_time(); +} + +void SRTC::update_time() { + time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24); + time_t current_time = time(0); + + //sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic. + //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by + //accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow + //rtc[] timestamp to remain valid for up to ~34 years from the last update, even if + //time_t overflows. calculation should be valid regardless of number representation, time_t size, + //or whether time_t is signed or unsigned. + time_t diff + = (current_time >= rtc_time) + ? (current_time - rtc_time) + : (std::numeric_limits::max() - rtc_time + current_time + 1); //compensate for overflow + if(diff > std::numeric_limits::max() / 2) diff = 0; //compensate for underflow + + if(diff > 0) { + unsigned second = rtc[ 0] + rtc[ 1] * 10; + unsigned minute = rtc[ 2] + rtc[ 3] * 10; + unsigned hour = rtc[ 4] + rtc[ 5] * 10; + unsigned day = rtc[ 6] + rtc[ 7] * 10; + unsigned month = rtc[ 8]; + unsigned year = rtc[ 9] + rtc[10] * 10 + rtc[11] * 100; + unsigned weekday = rtc[12]; + + day--; + month--; + year += 1000; + + second += diff; + while(second >= 60) { + second -= 60; + + minute++; + if(minute < 60) continue; + minute = 0; + + hour++; + if(hour < 24) continue; + hour = 0; + + day++; + weekday = (weekday + 1) % 7; + unsigned days = months[month % 12]; + if(days == 28) { + bool leapyear = false; + if((year % 4) == 0) { + leapyear = true; + if((year % 100) == 0 && (year % 400) != 0) leapyear = false; + } + if(leapyear) days++; + } + if(day < days) continue; + day = 0; + + month++; + if(month < 12) continue; + month = 0; + + year++; + } + + day++; + month++; + year -= 1000; + + rtc[ 0] = second % 10; + rtc[ 1] = second / 10; + rtc[ 2] = minute % 10; + rtc[ 3] = minute / 10; + rtc[ 4] = hour % 10; + rtc[ 5] = hour / 10; + rtc[ 6] = day % 10; + rtc[ 7] = day / 10; + rtc[ 8] = month; + rtc[ 9] = year % 10; + rtc[10] = (year / 10) % 10; + rtc[11] = year / 100; + rtc[12] = weekday % 7; + } + + rtc[16] = current_time >> 0; + rtc[17] = current_time >> 8; + rtc[18] = current_time >> 16; + rtc[19] = current_time >> 24; +} + +//returns day of week for specified date +//eg 0 = Sunday, 1 = Monday, ... 6 = Saturday +//usage: weekday(2008, 1, 1) returns weekday of January 1st, 2008 +unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) { + unsigned y = 1900, m = 1; //epoch is 1900-01-01 + unsigned sum = 0; //number of days passed since epoch + + year = max(1900, year); + month = max(1, min(12, month)); + day = max(1, min(31, day)); + + while(y < year) { + bool leapyear = false; + if((y % 4) == 0) { + leapyear = true; + if((y % 100) == 0 && (y % 400) != 0) leapyear = false; + } + sum += leapyear ? 366 : 365; + y++; + } + + while(m < month) { + unsigned days = months[m - 1]; + if(days == 28) { + bool leapyear = false; + if((y % 4) == 0) { + leapyear = true; + if((y % 100) == 0 && (y % 400) != 0) leapyear = false; + } + if(leapyear) days++; + } + sum += days; + m++; + } + + sum += day - 1; + return (sum + 1) % 7; //1900-01-01 was a Monday +} + +uint8 SRTC::read(unsigned addr) { + addr &= 0xffff; + + if(addr == 0x2800) { + if(rtc_mode != RtcRead) return 0x00; + + if(rtc_index < 0) { + update_time(); + rtc_index++; + return 0x0f; + } else if(rtc_index > 12) { + rtc_index = -1; + return 0x0f; + } else { + return rtc[rtc_index++]; + } + } + + return cpu.regs.mdr; +} + +void SRTC::write(unsigned addr, uint8 data) { + addr &= 0xffff; + + if(addr == 0x2801) { + data &= 0x0f; //only the low four bits are used + + if(data == 0x0d) { + rtc_mode = RtcRead; + rtc_index = -1; + return; + } + + if(data == 0x0e) { + rtc_mode = RtcCommand; + return; + } + + if(data == 0x0f) return; //unknown behavior + + if(rtc_mode == RtcWrite) { + if(rtc_index >= 0 && rtc_index < 12) { + rtc[rtc_index++] = data; + + if(rtc_index == 12) { + //day of week is automatically calculated and written + unsigned day = rtc[ 6] + rtc[ 7] * 10; + unsigned month = rtc[ 8]; + unsigned year = rtc[ 9] + rtc[10] * 10 + rtc[11] * 100; + year += 1000; + + rtc[rtc_index++] = weekday(year, month, day); + } + } + } else if(rtc_mode == RtcCommand) { + if(data == 0) { + rtc_mode = RtcWrite; + rtc_index = 0; + } else if(data == 4) { + rtc_mode = RtcReady; + rtc_index = -1; + for(unsigned i = 0; i < 13; i++) rtc[i] = 0; + } else { + //unknown behavior + rtc_mode = RtcReady; + } + } + } +} + +SRTC::SRTC() { +} + +} diff --git a/snes/chip/srtc/srtc.hpp b/snes/chip/srtc/srtc.hpp new file mode 100755 index 00000000..93dcbe51 --- /dev/null +++ b/snes/chip/srtc/srtc.hpp @@ -0,0 +1,27 @@ +class SRTC { +public: + uint8 rtc[20]; + + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); + + void serialize(serializer&); + SRTC(); + +private: + static const unsigned months[12]; + enum RtcMode { RtcReady, RtcCommand, RtcRead, RtcWrite }; + unsigned rtc_mode; + signed rtc_index; + + void update_time(); + unsigned weekday(unsigned year, unsigned month, unsigned day); +}; + +extern SRTC srtc; diff --git a/snes/chip/st0018/st0018.cpp b/snes/chip/st0018/st0018.cpp new file mode 100755 index 00000000..aefb278b --- /dev/null +++ b/snes/chip/st0018/st0018.cpp @@ -0,0 +1,126 @@ +#include + +#define ST0018_CPP +namespace SNES { + +ST0018 st0018; + +uint8 ST0018::mmio_read(unsigned addr) { + addr &= 0xffff; + if(addr == 0x3800) return regs.r3800; + if(addr == 0x3804) return regs.r3804; + return cpu.regs.mdr; +} + +void ST0018::mmio_write(unsigned addr, uint8 data) { + addr &= 0xffff; + + if(addr == 0x3802) { + switch(regs.mode) { + case Waiting: { + switch(data) { + case 0x01: regs.r3800 = regs.r3800_01; break; + case 0xaa: op_board_upload(); break; + case 0xb2: op_b2(); break; + case 0xb3: op_b3(); break; + case 0xb4: op_b4(); break; + case 0xb5: op_b5(); break; + case 0xf1: op_query_chip(); break; + case 0xf2: op_query_chip(); break; + default: fprintf(stdout, "* ST018 w3802::%.2x\n", data); break; + } + } return; + + case BoardUpload: { + op_board_upload(data); + } return; + } + } + + if(addr == 0x3804) { + regs.w3804 <<= 8; + regs.w3804 |= data; + regs.w3804 &= 0xffffff; + return; + } +} + +void ST0018::init() { +} + +void ST0018::load() { +} + +void ST0018::unload() { +} + +void ST0018::power() { + reset(); +} + +void ST0018::reset() { + regs.mode = Waiting; + regs.r3800 = 0x00; + regs.r3804 = 0x85; + regs.w3804 = 0; + for(unsigned i = 0; i < 97; i++) board[i] = 0; +} + +//=============== +//ST-0018 opcodes +//=============== + +void ST0018::op_board_upload() { + regs.mode = BoardUpload; + regs.counter = 0; + regs.r3800 = 0xe0; +} + +void ST0018::op_board_upload(uint8 data) { + board[regs.counter] = data; + regs.r3800 = 96 - regs.counter; + regs.counter++; + if(regs.counter >= 97) { + regs.mode = Waiting; + #if 0 + for(unsigned y = 0; y < 9; y++) { + for(unsigned x = 0; x < 9; x++) { + fprintf(stdout, "%.2x ", board[y * 9 + x]); + } + fprintf(stdout, "\n"); + } + for(unsigned n = 0; n < 16; n++) fprintf(stdout, "%.2x ", board[81 + n]); + fprintf(stdout, "\n\n"); + #endif + } +} + +void ST0018::op_b2() { + fprintf(stdout, "* ST018 w3802::b2\n"); + regs.r3800 = 0xe0; + regs.r3800_01 = 0; //unknown +} + +void ST0018::op_b3() { + fprintf(stdout, "* ST018 w3802::b3\n"); + regs.r3800 = 0xe0; + regs.r3800_01 = 1; //0 = player lost? +} + +void ST0018::op_b4() { + fprintf(stdout, "* ST018 w3802::b4\n"); + regs.r3800 = 0xe0; + regs.r3800_01 = 1; //0 = player won? +} + +void ST0018::op_b5() { + fprintf(stdout, "* ST018 w3802::b5\n"); + regs.r3800 = 0xe0; + regs.r3800_01 = 0; //1 = move will result in checkmate? +} + +void ST0018::op_query_chip() { + regs.r3800 = 0x00; +} + +} diff --git a/snes/chip/st0018/st0018.hpp b/snes/chip/st0018/st0018.hpp new file mode 100755 index 00000000..3fa381d9 --- /dev/null +++ b/snes/chip/st0018/st0018.hpp @@ -0,0 +1,52 @@ +class ST0018 { +public: + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + + enum mode_t { Waiting, BoardUpload }; + struct regs_t { + mode_t mode; + + uint8 r3800; + uint8 r3800_01; + uint8 r3804; + + unsigned w3804; + unsigned counter; + } regs; + + enum PieceID { + Pawn = 0x00, //foot soldier + Lance = 0x04, //incense chariot + Knight = 0x08, //cassia horse + Silver = 0x0c, //silver general + Gold = 0x10, //gold general + Rook = 0x14, //flying chariot + Bishop = 0x18, //angle mover + King = 0x1c, //king + }; + + enum PieceFlag { + PlayerA = 0x20, + PlayerB = 0x40, + }; + + uint8 board[9 * 9 + 16]; + +private: + void op_board_upload(); + void op_board_upload(uint8 data); + void op_b2(); + void op_b3(); + void op_b4(); + void op_b5(); + void op_query_chip(); +}; + +extern ST0018 st0018; diff --git a/snes/chip/sufamiturbo/serialization.cpp b/snes/chip/sufamiturbo/serialization.cpp new file mode 100755 index 00000000..526c3496 --- /dev/null +++ b/snes/chip/sufamiturbo/serialization.cpp @@ -0,0 +1,8 @@ +#ifdef SUFAMITURBO_CPP + +void SufamiTurbo::serialize(serializer &s) { + if(slotA.ram.data()) s.array(slotA.ram.data(), slotA.ram.size()); + if(slotB.ram.data()) s.array(slotB.ram.data(), slotB.ram.size()); +} + +#endif diff --git a/snes/chip/sufamiturbo/sufamiturbo.cpp b/snes/chip/sufamiturbo/sufamiturbo.cpp new file mode 100755 index 00000000..14fbb633 --- /dev/null +++ b/snes/chip/sufamiturbo/sufamiturbo.cpp @@ -0,0 +1,33 @@ +#include + +#define SUFAMITURBO_CPP +namespace SNES { + +#include "serialization.cpp" +SufamiTurbo sufamiturbo; + +void SufamiTurbo::load() { + slotA.ram.map(allocate(128 * 1024, 0xff), 128 * 1024); + slotB.ram.map(allocate(128 * 1024, 0xff), 128 * 1024); + + if(slotA.rom.data()) { + cartridge.nvram.append({ ".sts", slotA.ram.data(), slotA.ram.size(), Cartridge::Slot::SufamiTurboA }); + } else { + slotA.rom.map(allocate(128 * 1024, 0xff), 128 * 1024); + } + + if(slotB.rom.data()) { + cartridge.nvram.append({ ".sts", slotB.ram.data(), slotB.ram.size(), Cartridge::Slot::SufamiTurboB }); + } else { + slotB.rom.map(allocate(128 * 1024, 0xff), 128 * 1024); + } +} + +void SufamiTurbo::unload() { + slotA.rom.reset(); + slotA.ram.reset(); + slotB.rom.reset(); + slotB.ram.reset(); +} + +} diff --git a/snes/chip/sufamiturbo/sufamiturbo.hpp b/snes/chip/sufamiturbo/sufamiturbo.hpp new file mode 100755 index 00000000..b38d75b5 --- /dev/null +++ b/snes/chip/sufamiturbo/sufamiturbo.hpp @@ -0,0 +1,13 @@ +class SufamiTurbo { +public: + struct Slot { + MappedRAM rom; + MappedRAM ram; + } slotA, slotB; + + void load(); + void unload(); + void serialize(serializer&); +}; + +extern SufamiTurbo sufamiturbo; diff --git a/snes/chip/superfx/bus/bus.cpp b/snes/chip/superfx/bus/bus.cpp new file mode 100755 index 00000000..2ce33a7e --- /dev/null +++ b/snes/chip/superfx/bus/bus.cpp @@ -0,0 +1,37 @@ +#ifdef SUPERFX_CPP + +//ROM / RAM access from the S-CPU + +unsigned SuperFX::ROM::size() const { + return cartridge.rom.size(); +} + +uint8 SuperFX::ROM::read(unsigned addr) { + if(superfx.regs.sfr.g && superfx.regs.scmr.ron) { + static const uint8_t data[16] = { + 0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01, + }; + return data[addr & 15]; + } + return cartridge.rom.read(addr); +} + +void SuperFX::ROM::write(unsigned addr, uint8 data) { + cartridge.rom.write(addr, data); +} + +unsigned SuperFX::RAM::size() const { + return cartridge.ram.size(); +} + +uint8 SuperFX::RAM::read(unsigned addr) { + if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return cpu.regs.mdr; + return cartridge.ram.read(addr); +} + +void SuperFX::RAM::write(unsigned addr, uint8 data) { + cartridge.ram.write(addr, data); +} + +#endif diff --git a/snes/chip/superfx/bus/bus.hpp b/snes/chip/superfx/bus/bus.hpp new file mode 100755 index 00000000..6e698e68 --- /dev/null +++ b/snes/chip/superfx/bus/bus.hpp @@ -0,0 +1,11 @@ +struct ROM : Memory { + unsigned size() const; + uint8 read(unsigned); + void write(unsigned, uint8); +} rom; + +struct RAM : Memory { + unsigned size() const; + uint8 read(unsigned); + void write(unsigned, uint8); +} ram; diff --git a/snes/chip/superfx/core/core.cpp b/snes/chip/superfx/core/core.cpp new file mode 100755 index 00000000..92c2afd6 --- /dev/null +++ b/snes/chip/superfx/core/core.cpp @@ -0,0 +1,107 @@ +#ifdef SUPERFX_CPP + +#include "opcodes.cpp" +#include "opcode_table.cpp" + +uint8 SuperFX::color(uint8 source) { + if(regs.por.highnibble) return (regs.colr & 0xf0) | (source >> 4); + if(regs.por.freezehigh) return (regs.colr & 0xf0) | (source & 0x0f); + return source; +} + +void SuperFX::plot(uint8 x, uint8 y) { + uint8 color = regs.colr; + + if(regs.por.dither && regs.scmr.md != 3) { + if((x ^ y) & 1) color >>= 4; + color &= 0x0f; + } + + if(!regs.por.transparent) { + if(regs.scmr.md == 3) { + if(regs.por.freezehigh) { + if((color & 0x0f) == 0) return; + } else { + if(color == 0) return; + } + } else { + if((color & 0x0f) == 0) return; + } + } + + uint16 offset = (y << 5) + (x >> 3); + if(offset != pixelcache[0].offset) { + pixelcache_flush(pixelcache[1]); + pixelcache[1] = pixelcache[0]; + pixelcache[0].bitpend = 0x00; + pixelcache[0].offset = offset; + } + + x = (x & 7) ^ 7; + pixelcache[0].data[x] = color; + pixelcache[0].bitpend |= 1 << x; + if(pixelcache[0].bitpend == 0xff) { + pixelcache_flush(pixelcache[1]); + pixelcache[1] = pixelcache[0]; + pixelcache[0].bitpend = 0x00; + } +} + +uint8 SuperFX::rpix(uint8 x, uint8 y) { + pixelcache_flush(pixelcache[1]); + pixelcache_flush(pixelcache[0]); + + unsigned cn; //character number + switch(regs.por.obj ? 3 : regs.scmr.ht) { + case 0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break; + case 1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break; + case 2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break; + case 3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break; + } + unsigned bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 }; + unsigned addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2); + uint8 data = 0x00; + x = (x & 7) ^ 7; + + for(unsigned n = 0; n < bpp; n++) { + unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 }; + add_clocks(memory_access_speed); + data |= ((bus_read(addr + byte) >> x) & 1) << n; + } + + return data; +} + +void SuperFX::pixelcache_flush(pixelcache_t &cache) { + if(cache.bitpend == 0x00) return; + + uint8 x = cache.offset << 3; + uint8 y = cache.offset >> 5; + + unsigned cn; //character number + switch(regs.por.obj ? 3 : regs.scmr.ht) { + case 0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break; + case 1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break; + case 2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break; + case 3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break; + } + unsigned bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 }; + unsigned addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2); + + for(unsigned n = 0; n < bpp; n++) { + unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 }; + uint8 data = 0x00; + for(unsigned x = 0; x < 8; x++) data |= ((cache.data[x] >> n) & 1) << x; + if(cache.bitpend != 0xff) { + add_clocks(memory_access_speed); + data &= cache.bitpend; + data |= bus_read(addr + byte) & ~cache.bitpend; + } + add_clocks(memory_access_speed); + bus_write(addr + byte, data); + } + + cache.bitpend = 0x00; +} + +#endif diff --git a/snes/chip/superfx/core/core.hpp b/snes/chip/superfx/core/core.hpp new file mode 100755 index 00000000..1c13f1ce --- /dev/null +++ b/snes/chip/superfx/core/core.hpp @@ -0,0 +1,92 @@ +#include "registers.hpp" + +uint8 color(uint8 source); +void plot(uint8 x, uint8 y); +uint8 rpix(uint8 x, uint8 y); +void pixelcache_flush(pixelcache_t &cache); + +void (SuperFX::*opcode_table[1024])(); +void initialize_opcode_table(); + +//opcodes.cpp +template void op_adc_i(); +template void op_adc_r(); +template void op_add_i(); +template void op_add_r(); +void op_alt1(); +void op_alt2(); +void op_alt3(); +template void op_and_i(); +template void op_and_r(); +void op_asr(); +void op_bge(); +void op_bcc(); +void op_bcs(); +void op_beq(); +template void op_bic_i(); +template void op_bic_r(); +void op_blt(); +void op_bmi(); +void op_bne(); +void op_bpl(); +void op_bra(); +void op_bvc(); +void op_bvs(); +void op_cache(); +void op_cmode(); +template void op_cmp_r(); +void op_color(); +template void op_dec_r(); +void op_div2(); +void op_fmult(); +template void op_from_r(); +void op_getb(); +void op_getbl(); +void op_getbh(); +void op_getbs(); +void op_getc(); +void op_hib(); +template void op_ibt_r(); +template void op_inc_r(); +template void op_iwt_r(); +template void op_jmp_r(); +template void op_ldb_ir(); +template void op_ldw_ir(); +template void op_link(); +template void op_ljmp_r(); +template void op_lm_r(); +template void op_lms_r(); +void op_lmult(); +void op_lob(); +void op_loop(); +void op_lsr(); +void op_merge(); +template void op_mult_i(); +template void op_mult_r(); +void op_nop(); +void op_not(); +template void op_or_i(); +template void op_or_r(); +void op_plot(); +void op_ramb(); +void op_rol(); +void op_romb(); +void op_ror(); +void op_rpix(); +template void op_sbc_r(); +void op_sbk(); +void op_sex(); +template void op_sm_r(); +template void op_sms_r(); +template void op_stb_ir(); +void op_stop(); +template void op_stw_ir(); +template void op_sub_i(); +template void op_sub_r(); +void op_swap(); +template void op_to_r(); +template void op_umult_i(); +template void op_umult_r(); +template void op_with_r(); +template void op_xor_i(); +template void op_xor_r(); diff --git a/snes/chip/superfx/core/opcode_table.cpp b/snes/chip/superfx/core/opcode_table.cpp new file mode 100755 index 00000000..79082531 --- /dev/null +++ b/snes/chip/superfx/core/opcode_table.cpp @@ -0,0 +1,270 @@ +#ifdef SUPERFX_CPP + +void SuperFX::initialize_opcode_table() { + #define op4(id, name) \ + op(id+ 0, name< 1>) op(id+ 1, name< 2>) op(id+ 2, name< 3>) op(id+ 3, name< 4>) + + #define op6(id, name) \ + op(id+ 0, name< 8>) op(id+ 1, name< 9>) op(id+ 2, name<10>) op(id+ 3, name<11>) \ + op(id+ 4, name<12>) op(id+ 5, name<13>) + + #define op12(id, name) \ + op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \ + op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \ + op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) + + #define op15l(id, name) \ + op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \ + op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \ + op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) \ + op(id+12, name<12>) op(id+13, name<13>) op(id+14, name<14>) + + #define op15h(id, name) \ + op(id+ 0, name< 1>) op(id+ 1, name< 2>) op(id+ 2, name< 3>) op(id+ 3, name< 4>) \ + op(id+ 4, name< 5>) op(id+ 5, name< 6>) op(id+ 6, name< 7>) op(id+ 7, name< 8>) \ + op(id+ 8, name< 9>) op(id+ 9, name<10>) op(id+10, name<11>) op(id+11, name<12>) \ + op(id+12, name<13>) op(id+13, name<14>) op(id+14, name<15>) + + #define op16(id, name) \ + op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \ + op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \ + op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) \ + op(id+12, name<12>) op(id+13, name<13>) op(id+14, name<14>) op(id+15, name<15>) + + //====== + // ALT0 + //====== + + #define op(id, name) opcode_table[ 0 + id] = &SuperFX::op_##name; + op (0x00, stop) + op (0x01, nop) + op (0x02, cache) + op (0x03, lsr) + op (0x04, rol) + op (0x05, bra) + op (0x06, blt) + op (0x07, bge) + op (0x08, bne) + op (0x09, beq) + op (0x0a, bpl) + op (0x0b, bmi) + op (0x0c, bcc) + op (0x0d, bcs) + op (0x0e, bvc) + op (0x0f, bvs) + op16 (0x10, to_r) + op16 (0x20, with_r) + op12 (0x30, stw_ir) + op (0x3c, loop) + op (0x3d, alt1) + op (0x3e, alt2) + op (0x3f, alt3) + op12 (0x40, ldw_ir) + op (0x4c, plot) + op (0x4d, swap) + op (0x4e, color) + op (0x4f, not) + op16 (0x50, add_r) + op16 (0x60, sub_r) + op (0x70, merge) + op15h(0x71, and_r) + op16 (0x80, mult_r) + op (0x90, sbk) + op4 (0x91, link) + op (0x95, sex) + op (0x96, asr) + op (0x97, ror) + op6 (0x98, jmp_r) + op (0x9e, lob) + op (0x9f, fmult) + op16 (0xa0, ibt_r) + op16 (0xb0, from_r) + op (0xc0, hib) + op15h(0xc1, or_r) + op15l(0xd0, inc_r) + op (0xdf, getc) + op15l(0xe0, dec_r) + op (0xef, getb) + op16 (0xf0, iwt_r) + #undef op + + //====== + // ALT1 + //====== + + #define op(id, name) opcode_table[256 + id] = &SuperFX::op_##name; + op (0x00, stop) + op (0x01, nop) + op (0x02, cache) + op (0x03, lsr) + op (0x04, rol) + op (0x05, bra) + op (0x06, blt) + op (0x07, bge) + op (0x08, bne) + op (0x09, beq) + op (0x0a, bpl) + op (0x0b, bmi) + op (0x0c, bcc) + op (0x0d, bcs) + op (0x0e, bvc) + op (0x0f, bvs) + op16 (0x10, to_r) + op16 (0x20, with_r) + op12 (0x30, stb_ir) + op (0x3c, loop) + op (0x3d, alt1) + op (0x3e, alt2) + op (0x3f, alt3) + op12 (0x40, ldb_ir) + op (0x4c, rpix) + op (0x4d, swap) + op (0x4e, cmode) + op (0x4f, not) + op16 (0x50, adc_r) + op16 (0x60, sbc_r) + op (0x70, merge) + op15h(0x71, bic_r) + op16 (0x80, umult_r) + op (0x90, sbk) + op4 (0x91, link) + op (0x95, sex) + op (0x96, div2) + op (0x97, ror) + op6 (0x98, ljmp_r) + op (0x9e, lob) + op (0x9f, lmult) + op16 (0xa0, lms_r) + op16 (0xb0, from_r) + op (0xc0, hib) + op15h(0xc1, xor_r) + op15l(0xd0, inc_r) + op (0xdf, getc) + op15l(0xe0, dec_r) + op (0xef, getbh) + op16 (0xf0, lm_r) + #undef op + + //====== + // ALT2 + //====== + + #define op(id, name) opcode_table[512 + id] = &SuperFX::op_##name; + op (0x00, stop) + op (0x01, nop) + op (0x02, cache) + op (0x03, lsr) + op (0x04, rol) + op (0x05, bra) + op (0x06, blt) + op (0x07, bge) + op (0x08, bne) + op (0x09, beq) + op (0x0a, bpl) + op (0x0b, bmi) + op (0x0c, bcc) + op (0x0d, bcs) + op (0x0e, bvc) + op (0x0f, bvs) + op16 (0x10, to_r) + op16 (0x20, with_r) + op12 (0x30, stw_ir) + op (0x3c, loop) + op (0x3d, alt1) + op (0x3e, alt2) + op (0x3f, alt3) + op12 (0x40, ldw_ir) + op (0x4c, plot) + op (0x4d, swap) + op (0x4e, color) + op (0x4f, not) + op16 (0x50, add_i) + op16 (0x60, sub_i) + op (0x70, merge) + op15h(0x71, and_i) + op16 (0x80, mult_i) + op (0x90, sbk) + op4 (0x91, link) + op (0x95, sex) + op (0x96, asr) + op (0x97, ror) + op6 (0x98, jmp_r) + op (0x9e, lob) + op (0x9f, fmult) + op16 (0xa0, sms_r) + op16 (0xb0, from_r) + op (0xc0, hib) + op15h(0xc1, or_i) + op15l(0xd0, inc_r) + op (0xdf, ramb) + op15l(0xe0, dec_r) + op (0xef, getbl) + op16 (0xf0, sm_r) + #undef op + + //====== + // ALT3 + //====== + + #define op(id, name) opcode_table[768 + id] = &SuperFX::op_##name; + op (0x00, stop) + op (0x01, nop) + op (0x02, cache) + op (0x03, lsr) + op (0x04, rol) + op (0x05, bra) + op (0x06, blt) + op (0x07, bge) + op (0x08, bne) + op (0x09, beq) + op (0x0a, bpl) + op (0x0b, bmi) + op (0x0c, bcc) + op (0x0d, bcs) + op (0x0e, bvc) + op (0x0f, bvs) + op16 (0x10, to_r) + op16 (0x20, with_r) + op12 (0x30, stb_ir) + op (0x3c, loop) + op (0x3d, alt1) + op (0x3e, alt2) + op (0x3f, alt3) + op12 (0x40, ldb_ir) + op (0x4c, rpix) + op (0x4d, swap) + op (0x4e, cmode) + op (0x4f, not) + op16 (0x50, adc_i) + op16 (0x60, cmp_r) + op (0x70, merge) + op15h(0x71, bic_i) + op16 (0x80, umult_i) + op (0x90, sbk) + op4 (0x91, link) + op (0x95, sex) + op (0x96, div2) + op (0x97, ror) + op6 (0x98, ljmp_r) + op (0x9e, lob) + op (0x9f, lmult) + op16 (0xa0, lms_r) + op16 (0xb0, from_r) + op (0xc0, hib) + op15h(0xc1, xor_i) + op15l(0xd0, inc_r) + op (0xdf, romb) + op15l(0xe0, dec_r) + op (0xef, getbs) + op16 (0xf0, lm_r) + #undef op + + #undef op4 + #undef op6 + #undef op12 + #undef op15l + #undef op15h + #undef op16 +} + +#endif diff --git a/snes/chip/superfx/core/opcodes.cpp b/snes/chip/superfx/core/opcodes.cpp new file mode 100755 index 00000000..7d2f13a2 --- /dev/null +++ b/snes/chip/superfx/core/opcodes.cpp @@ -0,0 +1,661 @@ +#ifdef SUPERFX_CPP + +//$00 stop +void SuperFX::op_stop() { + if(regs.cfgr.irq == 0) { + regs.sfr.irq = 1; + cpu.regs.irq = 1; + } + + regs.sfr.g = 0; + regs.pipeline = 0x01; + regs.reset(); +} + +//$01 nop +void SuperFX::op_nop() { + regs.reset(); +} + +//$02 cache +void SuperFX::op_cache() { + if(regs.cbr != (regs.r[15] & 0xfff0)) { + regs.cbr = regs.r[15] & 0xfff0; + cache_flush(); + } + regs.reset(); +} + +//$03 lsr +void SuperFX::op_lsr() { + regs.sfr.cy = (regs.sr() & 1); + regs.dr() = regs.sr() >> 1; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$04 rol +void SuperFX::op_rol() { + bool carry = (regs.sr() & 0x8000); + regs.dr() = (regs.sr() << 1) | regs.sfr.cy; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.cy = carry; + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$05 bra e +void SuperFX::op_bra() { + regs.r[15] += (int8)pipe(); +} + +//$06 blt e +void SuperFX::op_blt() { + int e = (int8)pipe(); + if((regs.sfr.s ^ regs.sfr.ov) == 0) regs.r[15] += e; +} + +//$07 bge e +void SuperFX::op_bge() { + int e = (int8)pipe(); + if((regs.sfr.s ^ regs.sfr.ov) == 1) regs.r[15] += e; +} + +//$08 bne e +void SuperFX::op_bne() { + int e = (int8)pipe(); + if(regs.sfr.z == 0) regs.r[15] += e; +} + +//$09 beq e +void SuperFX::op_beq() { + int e = (int8)pipe(); + if(regs.sfr.z == 1) regs.r[15] += e; +} + +//$0a bpl e +void SuperFX::op_bpl() { + int e = (int8)pipe(); + if(regs.sfr.s == 0) regs.r[15] += e; +} + +//$0b bmi e +void SuperFX::op_bmi() { + int e = (int8)pipe(); + if(regs.sfr.s == 1) regs.r[15] += e; +} + +//$0c bcc e +void SuperFX::op_bcc() { + int e = (int8)pipe(); + if(regs.sfr.cy == 0) regs.r[15] += e; +} + +//$0d bcs e +void SuperFX::op_bcs() { + int e = (int8)pipe(); + if(regs.sfr.cy == 1) regs.r[15] += e; +} + +//$0e bvc e +void SuperFX::op_bvc() { + int e = (int8)pipe(); + if(regs.sfr.ov == 0) regs.r[15] += e; +} + +//$0f bvs e +void SuperFX::op_bvs() { + int e = (int8)pipe(); + if(regs.sfr.ov == 1) regs.r[15] += e; +} + +//$10-1f(b0): to rN +//$10-1f(b1): move rN +template void SuperFX::op_to_r() { + if(regs.sfr.b == 0) { + regs.dreg = n; + } else { + regs.r[n] = regs.sr(); + regs.reset(); + } +} + +//$20-2f: with rN +template void SuperFX::op_with_r() { + regs.sreg = n; + regs.dreg = n; + regs.sfr.b = 1; +} + +//$30-3b(alt0): stw (rN) +template void SuperFX::op_stw_ir() { + regs.ramaddr = regs.r[n]; + rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0); + rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8); + regs.reset(); +} + +//$30-3b(alt1): stb (rN) +template void SuperFX::op_stb_ir() { + regs.ramaddr = regs.r[n]; + rambuffer_write(regs.ramaddr, regs.sr()); + regs.reset(); +} + +//$3c loop +void SuperFX::op_loop() { + regs.r[12]--; + regs.sfr.s = (regs.r[12] & 0x8000); + regs.sfr.z = (regs.r[12] == 0); + if(!regs.sfr.z) regs.r[15] = regs.r[13]; + regs.reset(); +} + +//$3d alt1 +void SuperFX::op_alt1() { + regs.sfr.b = 0; + regs.sfr.alt1 = 1; +} + +//$3e alt2 +void SuperFX::op_alt2() { + regs.sfr.b = 0; + regs.sfr.alt2 = 1; +} + +//$3f alt3 +void SuperFX::op_alt3() { + regs.sfr.b = 0; + regs.sfr.alt1 = 1; + regs.sfr.alt2 = 1; +} + +//$40-4b(alt0): ldw (rN) +template void SuperFX::op_ldw_ir() { + regs.ramaddr = regs.r[n]; + uint16_t data; + data = rambuffer_read(regs.ramaddr ^ 0) << 0; + data |= rambuffer_read(regs.ramaddr ^ 1) << 8; + regs.dr() = data; + regs.reset(); +} + +//$40-4b(alt1): ldb (rN) +template void SuperFX::op_ldb_ir() { + regs.ramaddr = regs.r[n]; + regs.dr() = rambuffer_read(regs.ramaddr); + regs.reset(); +} + +//$4c(alt0): plot +void SuperFX::op_plot() { + plot(regs.r[1], regs.r[2]); + regs.r[1]++; + regs.reset(); +} + +//$4c(alt1): rpix +void SuperFX::op_rpix() { + regs.dr() = rpix(regs.r[1], regs.r[2]); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$4d: swap +void SuperFX::op_swap() { + regs.dr() = (regs.sr() >> 8) | (regs.sr() << 8); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$4e(alt0): color +void SuperFX::op_color() { + regs.colr = color(regs.sr()); + regs.reset(); +} + +//$4e(alt1): cmode +void SuperFX::op_cmode() { + regs.por = regs.sr(); + regs.reset(); +} + +//$4f: not +void SuperFX::op_not() { + regs.dr() = ~regs.sr(); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$50-5f(alt0): add rN +template void SuperFX::op_add_r() { + int r = regs.sr() + regs.r[n]; + regs.sfr.ov = ~(regs.sr() ^ regs.r[n]) & (regs.r[n] ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0x10000); + regs.sfr.z = ((uint16_t)r == 0); + regs.dr() = r; + regs.reset(); +} + +//$50-5f(alt1): adc rN +template void SuperFX::op_adc_r() { + int r = regs.sr() + regs.r[n] + regs.sfr.cy; + regs.sfr.ov = ~(regs.sr() ^ regs.r[n]) & (regs.r[n] ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0x10000); + regs.sfr.z = ((uint16_t)r == 0); + regs.dr() = r; + regs.reset(); +} + +//$50-5f(alt2): add #N +template void SuperFX::op_add_i() { + int r = regs.sr() + n; + regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0x10000); + regs.sfr.z = ((uint16_t)r == 0); + regs.dr() = r; + regs.reset(); +} + +//$50-5f(alt3): adc #N +template void SuperFX::op_adc_i() { + int r = regs.sr() + n + regs.sfr.cy; + regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0x10000); + regs.sfr.z = ((uint16_t)r == 0); + regs.dr() = r; + regs.reset(); +} + +//$60-6f(alt0): sub rN +template void SuperFX::op_sub_r() { + int r = regs.sr() - regs.r[n]; + regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0); + regs.sfr.z = ((uint16_t)r == 0); + regs.dr() = r; + regs.reset(); +} + +//$60-6f(alt1): sbc rN +template void SuperFX::op_sbc_r() { + int r = regs.sr() - regs.r[n] - !regs.sfr.cy; + regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0); + regs.sfr.z = ((uint16_t)r == 0); + regs.dr() = r; + regs.reset(); +} + +//$60-6f(alt2): sub #N +template void SuperFX::op_sub_i() { + int r = regs.sr() - n; + regs.sfr.ov = (regs.sr() ^ n) & (regs.sr() ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0); + regs.sfr.z = ((uint16_t)r == 0); + regs.dr() = r; + regs.reset(); +} + +//$60-6f(alt3): cmp rN +template void SuperFX::op_cmp_r() { + int r = regs.sr() - regs.r[n]; + regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000; + regs.sfr.s = (r & 0x8000); + regs.sfr.cy = (r >= 0); + regs.sfr.z = ((uint16_t)r == 0); + regs.reset(); +} + +//$70: merge +void SuperFX::op_merge() { + regs.dr() = (regs.r[7] & 0xff00) | (regs.r[8] >> 8); + regs.sfr.ov = (regs.dr() & 0xc0c0); + regs.sfr.s = (regs.dr() & 0x8080); + regs.sfr.cy = (regs.dr() & 0xe0e0); + regs.sfr.z = (regs.dr() & 0xf0f0); + regs.reset(); +} + +//$71-7f(alt0): and rN +template void SuperFX::op_and_r() { + regs.dr() = regs.sr() & regs.r[n]; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$71-7f(alt1): bic rN +template void SuperFX::op_bic_r() { + regs.dr() = regs.sr() & ~regs.r[n]; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$71-7f(alt2): and #N +template void SuperFX::op_and_i() { + regs.dr() = regs.sr() & n; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$71-7f(alt3): bic #N +template void SuperFX::op_bic_i() { + regs.dr() = regs.sr() & ~n; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$80-8f(alt0): mult rN +template void SuperFX::op_mult_r() { + regs.dr() = (int8)regs.sr() * (int8)regs.r[n]; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); + if(!regs.cfgr.ms0) add_clocks(2); +} + +//$80-8f(alt1): umult rN +template void SuperFX::op_umult_r() { + regs.dr() = (uint8)regs.sr() * (uint8)regs.r[n]; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); + if(!regs.cfgr.ms0) add_clocks(2); +} + +//$80-8f(alt2): mult #N +template void SuperFX::op_mult_i() { + regs.dr() = (int8)regs.sr() * (int8)n; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); + if(!regs.cfgr.ms0) add_clocks(2); +} + +//$80-8f(alt3): umult #N +template void SuperFX::op_umult_i() { + regs.dr() = (uint8)regs.sr() * (uint8)n; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); + if(!regs.cfgr.ms0) add_clocks(2); +} + +//$90: sbk +void SuperFX::op_sbk() { + rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0); + rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8); + regs.reset(); +} + +//$91-94: link #N +template void SuperFX::op_link() { + regs.r[11] = regs.r[15] + n; + regs.reset(); +} + +//$95: sex +void SuperFX::op_sex() { + regs.dr() = (int8)regs.sr(); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$96(alt0): asr +void SuperFX::op_asr() { + regs.sfr.cy = (regs.sr() & 1); + regs.dr() = (int16_t)regs.sr() >> 1; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$96(alt1): div2 +void SuperFX::op_div2() { + regs.sfr.cy = (regs.sr() & 1); + regs.dr() = ((int16_t)regs.sr() >> 1) + ((regs.sr() + 1) >> 16); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$97: ror +void SuperFX::op_ror() { + bool carry = (regs.sr() & 1); + regs.dr() = (regs.sfr.cy << 15) | (regs.sr() >> 1); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.cy = carry; + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$98-9d(alt0): jmp rN +template void SuperFX::op_jmp_r() { + regs.r[15] = regs.r[n]; + regs.reset(); +} + +//$98-9d(alt1): ljmp rN +template void SuperFX::op_ljmp_r() { + regs.pbr = regs.r[n] & 0x7f; + regs.r[15] = regs.sr(); + regs.cbr = regs.r[15] & 0xfff0; + cache_flush(); + regs.reset(); +} + +//$9e: lob +void SuperFX::op_lob() { + regs.dr() = regs.sr() & 0xff; + regs.sfr.s = (regs.dr() & 0x80); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$9f(alt0): fmult +void SuperFX::op_fmult() { + uint32_t result = (int16_t)regs.sr() * (int16_t)regs.r[6]; + regs.dr() = result >> 16; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.cy = (result & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); + add_clocks(4 + (regs.cfgr.ms0 << 2)); +} + +//$9f(alt1): lmult +void SuperFX::op_lmult() { + uint32_t result = (int16_t)regs.sr() * (int16_t)regs.r[6]; + regs.r[4] = result; + regs.dr() = result >> 16; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.cy = (result & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); + add_clocks(4 + (regs.cfgr.ms0 << 2)); +} + +//$a0-af(alt0): ibt rN,#pp +template void SuperFX::op_ibt_r() { + regs.r[n] = (int8)pipe(); + regs.reset(); +} + +//$a0-af(alt1): lms rN,(yy) +template void SuperFX::op_lms_r() { + regs.ramaddr = pipe() << 1; + uint16_t data; + data = rambuffer_read(regs.ramaddr ^ 0) << 0; + data |= rambuffer_read(regs.ramaddr ^ 1) << 8; + regs.r[n] = data; + regs.reset(); +} + +//$a0-af(alt2): sms (yy),rN +template void SuperFX::op_sms_r() { + regs.ramaddr = pipe() << 1; + rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0); + rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8); + regs.reset(); +} + +//$b0-bf(b0): from rN +//$b0-bf(b1): moves rN +template void SuperFX::op_from_r() { + if(regs.sfr.b == 0) { + regs.sreg = n; + } else { + regs.dr() = regs.r[n]; + regs.sfr.ov = (regs.dr() & 0x80); + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); + } +} + +//$c0: hib +void SuperFX::op_hib() { + regs.dr() = regs.sr() >> 8; + regs.sfr.s = (regs.dr() & 0x80); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$c1-cf(alt0): or rN +template void SuperFX::op_or_r() { + regs.dr() = regs.sr() | regs.r[n]; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$c1-cf(alt1): xor rN +template void SuperFX::op_xor_r() { + regs.dr() = regs.sr() ^ regs.r[n]; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$c1-cf(alt2): or #N +template void SuperFX::op_or_i() { + regs.dr() = regs.sr() | n; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$c1-cf(alt3): xor #N +template void SuperFX::op_xor_i() { + regs.dr() = regs.sr() ^ n; + regs.sfr.s = (regs.dr() & 0x8000); + regs.sfr.z = (regs.dr() == 0); + regs.reset(); +} + +//$d0-de: inc rN +template void SuperFX::op_inc_r() { + regs.r[n]++; + regs.sfr.s = (regs.r[n] & 0x8000); + regs.sfr.z = (regs.r[n] == 0); + regs.reset(); +} + +//$df(alt0): getc +void SuperFX::op_getc() { + regs.colr = color(rombuffer_read()); + regs.reset(); +} + +//$df(alt2): ramb +void SuperFX::op_ramb() { + rambuffer_sync(); + regs.rambr = regs.sr(); + regs.reset(); +} + +//$df(alt3): romb +void SuperFX::op_romb() { + rombuffer_sync(); + regs.rombr = regs.sr() & 0x7f; + regs.reset(); +} + +//$e0-ee: dec rN +template void SuperFX::op_dec_r() { + regs.r[n]--; + regs.sfr.s = (regs.r[n] & 0x8000); + regs.sfr.z = (regs.r[n] == 0); + regs.reset(); +} + +//$ef(alt0): getb +void SuperFX::op_getb() { + regs.dr() = rombuffer_read(); + regs.reset(); +} + +//$ef(alt1): getbh +void SuperFX::op_getbh() { + regs.dr() = (rombuffer_read() << 8) | (regs.sr() & 0x00ff); + regs.reset(); +} + +//$ef(alt2): getbl +void SuperFX::op_getbl() { + regs.dr() = (regs.sr() & 0xff00) | (rombuffer_read() << 0); + regs.reset(); +} + +//$ef(alt3): getbs +void SuperFX::op_getbs() { + regs.dr() = (int8)rombuffer_read(); + regs.reset(); +} + +//$f0-ff(alt0): iwt rN,#xx +template void SuperFX::op_iwt_r() { + uint16_t data; + data = pipe() << 0; + data |= pipe() << 8; + regs.r[n] = data; + regs.reset(); +} + +//$f0-ff(alt1): lm rN,(xx) +template void SuperFX::op_lm_r() { + regs.ramaddr = pipe() << 0; + regs.ramaddr |= pipe() << 8; + uint16_t data; + data = rambuffer_read(regs.ramaddr ^ 0) << 0; + data |= rambuffer_read(regs.ramaddr ^ 1) << 8; + regs.r[n] = data; + regs.reset(); +} + +//$f0-ff(alt2): sm (xx),rN +template void SuperFX::op_sm_r() { + regs.ramaddr = pipe() << 0; + regs.ramaddr |= pipe() << 8; + rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0); + rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8); + regs.reset(); +} + +#endif diff --git a/snes/chip/superfx/core/registers.hpp b/snes/chip/superfx/core/registers.hpp new file mode 100755 index 00000000..ac193a8a --- /dev/null +++ b/snes/chip/superfx/core/registers.hpp @@ -0,0 +1,176 @@ +//accepts a callback binding so r14 writes can trigger ROM buffering transparently +struct reg16_t { + uint16 data; + function on_modify; + + inline operator unsigned() const { return data; } + inline uint16 assign(uint16 i) { + if(on_modify) on_modify(i); + else data = i; + return data; + } + + inline unsigned operator++() { return assign(data + 1); } + inline unsigned operator--() { return assign(data - 1); } + inline unsigned operator++(int) { unsigned r = data; assign(data + 1); return r; } + inline unsigned operator--(int) { unsigned r = data; assign(data - 1); return r; } + inline unsigned operator = (unsigned i) { return assign(i); } + inline unsigned operator |= (unsigned i) { return assign(data | i); } + inline unsigned operator ^= (unsigned i) { return assign(data ^ i); } + inline unsigned operator &= (unsigned i) { return assign(data & i); } + inline unsigned operator <<= (unsigned i) { return assign(data << i); } + inline unsigned operator >>= (unsigned i) { return assign(data >> i); } + inline unsigned operator += (unsigned i) { return assign(data + i); } + inline unsigned operator -= (unsigned i) { return assign(data - i); } + inline unsigned operator *= (unsigned i) { return assign(data * i); } + inline unsigned operator /= (unsigned i) { return assign(data / i); } + inline unsigned operator %= (unsigned i) { return assign(data % i); } + + inline unsigned operator = (const reg16_t& i) { return assign(i); } + + reg16_t() : data(0) {} + reg16_t(const reg16_t&) = delete; +}; + +struct sfr_t { + bool irq; //interrupt flag + bool b; //WITH flag + bool ih; //immediate higher 8-bit flag + bool il; //immediate lower 8-bit flag + bool alt2; //ALT2 mode + bool alt1; //ALT2 instruction mode + bool r; //ROM r14 read flag + bool g; //GO flag + bool ov; //overflow flag + bool s; //sign flag + bool cy; //carry flag + bool z; //zero flag + + operator unsigned() const { + return (irq << 15) | (b << 12) | (ih << 11) | (il << 10) | (alt2 << 9) | (alt1 << 8) + | (r << 6) | (g << 5) | (ov << 4) | (s << 3) | (cy << 2) | (z << 1); + } + + sfr_t& operator=(uint16_t data) { + irq = data & 0x8000; + b = data & 0x1000; + ih = data & 0x0800; + il = data & 0x0400; + alt2 = data & 0x0200; + alt1 = data & 0x0100; + r = data & 0x0040; + g = data & 0x0020; + ov = data & 0x0010; + s = data & 0x0008; + cy = data & 0x0004; + z = data & 0x0002; + return *this; + } +}; + +struct scmr_t { + unsigned ht; + bool ron; + bool ran; + unsigned md; + + operator unsigned() const { + return ((ht >> 1) << 5) | (ron << 4) | (ran << 3) | ((ht & 1) << 2) | (md); + } + + scmr_t& operator=(uint8 data) { + ht = (bool)(data & 0x20) << 1; + ht |= (bool)(data & 0x04) << 0; + ron = data & 0x10; + ran = data & 0x08; + md = data & 0x03; + return *this; + } +}; + +struct por_t { + bool obj; + bool freezehigh; + bool highnibble; + bool dither; + bool transparent; + + operator unsigned() const { + return (obj << 4) | (freezehigh << 3) | (highnibble << 2) | (dither << 1) | (transparent); + } + + por_t& operator=(uint8 data) { + obj = data & 0x10; + freezehigh = data & 0x08; + highnibble = data & 0x04; + dither = data & 0x02; + transparent = data & 0x01; + return *this; + } +}; + +struct cfgr_t { + bool irq; + bool ms0; + + operator unsigned() const { + return (irq << 7) | (ms0 << 5); + } + + cfgr_t& operator=(uint8 data) { + irq = data & 0x80; + ms0 = data & 0x20; + return *this; + } +}; + +struct regs_t { + uint8 pipeline; + uint16 ramaddr; + + reg16_t r[16]; //general purpose registers + sfr_t sfr; //status flag register + uint8 pbr; //program bank register + uint8 rombr; //game pack ROM bank register + bool rambr; //game pack RAM bank register + uint16 cbr; //cache base register + uint8 scbr; //screen base register + scmr_t scmr; //screen mode register + uint8 colr; //color register + por_t por; //plot option register + bool bramr; //back-up RAM register + uint8 vcr; //version code register + cfgr_t cfgr; //config register + bool clsr; //clock select register + + unsigned romcl; //clock ticks until romdr is valid + uint8 romdr; //ROM buffer data register + + unsigned ramcl; //clock ticks until ramdr is valid + uint16 ramar; //RAM buffer address register + uint8 ramdr; //RAM buffer data register + + unsigned sreg, dreg; + reg16_t& sr() { return r[sreg]; } //source register (from) + reg16_t& dr() { return r[dreg]; } //destination register (to) + + void reset() { + sfr.b = 0; + sfr.alt1 = 0; + sfr.alt2 = 0; + + sreg = 0; + dreg = 0; + } +} regs; + +struct cache_t { + uint8 buffer[512]; + bool valid[32]; +} cache; + +struct pixelcache_t { + uint16 offset; + uint8 bitpend; + uint8 data[8]; +} pixelcache[2]; diff --git a/snes/chip/superfx/disasm/disasm.cpp b/snes/chip/superfx/disasm/disasm.cpp new file mode 100755 index 00000000..f3454e60 --- /dev/null +++ b/snes/chip/superfx/disasm/disasm.cpp @@ -0,0 +1,279 @@ +#ifdef SUPERFX_CPP + +void SuperFX::disassemble_opcode(char *output) { + *output = 0; + + if(!regs.sfr.alt2) { + if(!regs.sfr.alt1) { + disassemble_alt0(output); + } else { + disassemble_alt1(output); + } + } else { + if(!regs.sfr.alt1) { + disassemble_alt2(output); + } else { + disassemble_alt3(output); + } + } + + unsigned length = strlen(output); + while(length++ < 20) strcat(output, " "); +} + +#define case4(id) \ + case id+ 0: case id+ 1: case id+ 2: case id+ 3 +#define case6(id) \ + case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5 +#define case12(id) \ + case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \ + case id+ 8: case id+ 9: case id+10: case id+11 +#define case15(id) \ + case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \ + case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14 +#define case16(id) \ + case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \ + case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14: case id+15 + +#define op0 regs.pipeline +#define op1 bus_read((regs.pbr << 16) + regs.r[15] + 0) +#define op2 bus_read((regs.pbr << 16) + regs.r[15] + 1) + +void SuperFX::disassemble_alt0(char *output) { + char t[256] = ""; + switch(op0) { + case (0x00): sprintf(t, "stop"); break; + case (0x01): sprintf(t, "nop"); break; + case (0x02): sprintf(t, "cache"); break; + case (0x03): sprintf(t, "lsr"); break; + case (0x04): sprintf(t, "rol"); break; + case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break; + case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break; + case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break; + case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break; + case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break; + case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break; + case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break; + case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break; + case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break; + case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break; + case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break; + case16(0x10): sprintf(t, "to r%u", op0 & 15); break; + case16(0x20): sprintf(t, "with r%u", op0 & 15); break; + case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break; + case (0x3c): sprintf(t, "loop"); break; + case (0x3d): sprintf(t, "alt1"); break; + case (0x3e): sprintf(t, "alt2"); break; + case (0x3f): sprintf(t, "alt3"); break; + case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break; + case (0x4c): sprintf(t, "plot"); break; + case (0x4d): sprintf(t, "swap"); break; + case (0x4e): sprintf(t, "color"); break; + case (0x4f): sprintf(t, "not"); break; + case16(0x50): sprintf(t, "add r%u", op0 & 15); break; + case16(0x60): sprintf(t, "sub r%u", op0 & 15); break; + case (0x70): sprintf(t, "merge"); break; + case15(0x71): sprintf(t, "and r%u", op0 & 15); break; + case16(0x80): sprintf(t, "mult r%u", op0 & 15); break; + case (0x90): sprintf(t, "sbk"); break; + case4 (0x91): sprintf(t, "link #%u", op0 & 15); break; + case (0x95): sprintf(t, "sex"); break; + case (0x96): sprintf(t, "asr"); break; + case (0x97): sprintf(t, "ror"); break; + case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break; + case (0x9e): sprintf(t, "lob"); break; + case (0x9f): sprintf(t, "fmult"); break; + case16(0xa0): sprintf(t, "ibt r%u,#$%.2x", op0 & 15, op1); break; + case16(0xb0): sprintf(t, "from r%u", op0 & 15); break; + case (0xc0): sprintf(t, "hib"); + case15(0xc1): sprintf(t, "or r%u", op0 & 15); break; + case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break; + case (0xdf): sprintf(t, "getc"); break; + case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break; + case (0xef): sprintf(t, "getb"); break; + case16(0xf0): sprintf(t, "iwt r%u,#$%.2x%.2x", op0 & 15, op2, op1); break; + } + strcat(output, t); +} + +void SuperFX::disassemble_alt1(char *output) { + char t[256] = ""; + switch(op0) { + case (0x00): sprintf(t, "stop"); break; + case (0x01): sprintf(t, "nop"); break; + case (0x02): sprintf(t, "cache"); break; + case (0x03): sprintf(t, "lsr"); break; + case (0x04): sprintf(t, "rol"); break; + case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break; + case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break; + case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break; + case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break; + case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break; + case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break; + case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break; + case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break; + case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break; + case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break; + case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break; + case16(0x10): sprintf(t, "to r%u", op0 & 15); break; + case16(0x20): sprintf(t, "with r%u", op0 & 15); break; + case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break; + case (0x3c): sprintf(t, "loop"); break; + case (0x3d): sprintf(t, "alt1"); break; + case (0x3e): sprintf(t, "alt2"); break; + case (0x3f): sprintf(t, "alt3"); break; + case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break; + case (0x4c): sprintf(t, "rpix"); break; + case (0x4d): sprintf(t, "swap"); break; + case (0x4e): sprintf(t, "cmode"); break; + case (0x4f): sprintf(t, "not"); break; + case16(0x50): sprintf(t, "adc r%u", op0 & 15); break; + case16(0x60): sprintf(t, "sbc r%u", op0 & 15); break; + case (0x70): sprintf(t, "merge"); break; + case15(0x71): sprintf(t, "bic r%u", op0 & 15); break; + case16(0x80): sprintf(t, "umult r%u", op0 & 15); break; + case (0x90): sprintf(t, "sbk"); break; + case4 (0x91): sprintf(t, "link #%u", op0 & 15); break; + case (0x95): sprintf(t, "sex"); break; + case (0x96): sprintf(t, "div2"); break; + case (0x97): sprintf(t, "ror"); break; + case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break; + case (0x9e): sprintf(t, "lob"); break; + case (0x9f): sprintf(t, "lmult"); break; + case16(0xa0): sprintf(t, "lms r%u,(#$%.4x)", op0 & 15, op1 << 1); break; + case16(0xb0): sprintf(t, "from r%u", op0 & 15); break; + case (0xc0): sprintf(t, "hib"); break; + case15(0xc1): sprintf(t, "xor r%u", op0 & 15); break; + case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break; + case (0xdf): sprintf(t, "getc"); break; + case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break; + case (0xef): sprintf(t, "getbh"); break; + case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break; + } + strcat(output, t); +} + +void SuperFX::disassemble_alt2(char *output) { + char t[256] = ""; + switch(op0) { + case (0x00): sprintf(t, "stop"); break; + case (0x01): sprintf(t, "nop"); break; + case (0x02): sprintf(t, "cache"); break; + case (0x03): sprintf(t, "lsr"); break; + case (0x04): sprintf(t, "rol"); break; + case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break; + case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break; + case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break; + case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break; + case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break; + case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break; + case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break; + case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break; + case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break; + case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break; + case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break; + case16(0x10): sprintf(t, "to r%u", op0 & 15); break; + case16(0x20): sprintf(t, "with r%u", op0 & 15); break; + case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break; + case (0x3c): sprintf(t, "loop"); break; + case (0x3d): sprintf(t, "alt1"); break; + case (0x3e): sprintf(t, "alt2"); break; + case (0x3f): sprintf(t, "alt3"); break; + case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break; + case (0x4c): sprintf(t, "plot"); break; + case (0x4d): sprintf(t, "swap"); break; + case (0x4e): sprintf(t, "color"); break; + case (0x4f): sprintf(t, "not"); break; + case16(0x50): sprintf(t, "add #%u", op0 & 15); break; + case16(0x60): sprintf(t, "sub #%u", op0 & 15); break; + case (0x70): sprintf(t, "merge"); break; + case15(0x71): sprintf(t, "and #%u", op0 & 15); break; + case16(0x80): sprintf(t, "mult #%u", op0 & 15); break; + case (0x90): sprintf(t, "sbk"); break; + case4 (0x91): sprintf(t, "link #%u", op0 & 15); break; + case (0x95): sprintf(t, "sex"); break; + case (0x96): sprintf(t, "asr"); break; + case (0x97): sprintf(t, "ror"); break; + case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break; + case (0x9e): sprintf(t, "lob"); break; + case (0x9f): sprintf(t, "fmult"); break; + case16(0xa0): sprintf(t, "sms r%u,(#$%.4x)", op0 & 15, op1 << 1); break; + case16(0xb0): sprintf(t, "from r%u", op0 & 15); break; + case (0xc0): sprintf(t, "hib"); break; + case15(0xc1): sprintf(t, "or #%u", op0 & 15); break; + case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break; + case (0xdf): sprintf(t, "ramb"); break; + case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break; + case (0xef): sprintf(t, "getbl"); break; + case16(0xf0): sprintf(t, "sm r%u", op0 & 15); break; + } + strcat(output, t); +} + +void SuperFX::disassemble_alt3(char *output) { + char t[256] = ""; + switch(op0) { + case (0x00): sprintf(t, "stop"); break; + case (0x01): sprintf(t, "nop"); break; + case (0x02): sprintf(t, "cache"); break; + case (0x03): sprintf(t, "lsr"); break; + case (0x04): sprintf(t, "rol"); break; + case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break; + case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break; + case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break; + case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break; + case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break; + case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break; + case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break; + case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break; + case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break; + case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break; + case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break; + case16(0x10): sprintf(t, "to r%u", op0 & 15); break; + case16(0x20): sprintf(t, "with r%u", op0 & 15); break; + case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break; + case (0x3c): sprintf(t, "loop"); break; + case (0x3d): sprintf(t, "alt1"); break; + case (0x3e): sprintf(t, "alt2"); break; + case (0x3f): sprintf(t, "alt3"); break; + case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break; + case (0x4c): sprintf(t, "rpix"); break; + case (0x4d): sprintf(t, "swap"); break; + case (0x4e): sprintf(t, "cmode"); break; + case (0x4f): sprintf(t, "not"); break; + case16(0x50): sprintf(t, "adc #%u", op0 & 15); break; + case16(0x60): sprintf(t, "cmp r%u", op0 & 15); break; + case (0x70): sprintf(t, "merge"); break; + case15(0x71): sprintf(t, "bic #%u", op0 & 15); break; + case16(0x80): sprintf(t, "umult #%u", op0 & 15); break; + case (0x90): sprintf(t, "sbk"); break; + case4 (0x91): sprintf(t, "link #%u", op0 & 15); break; + case (0x95): sprintf(t, "sex"); break; + case (0x96): sprintf(t, "div2"); break; + case (0x97): sprintf(t, "ror"); break; + case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break; + case (0x9e): sprintf(t, "lob"); break; + case (0x9f): sprintf(t, "lmult"); break; + case16(0xa0): sprintf(t, "lms r%u", op0 & 15); break; + case16(0xb0): sprintf(t, "from r%u", op0 & 15); break; + case (0xc0): sprintf(t, "hib"); break; + case15(0xc1): sprintf(t, "xor #%u", op0 & 15); break; + case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break; + case (0xdf): sprintf(t, "romb"); break; + case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break; + case (0xef): sprintf(t, "getbs"); break; + case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break; + } + strcat(output, t); +} + +#undef case4 +#undef case6 +#undef case12 +#undef case15 +#undef case16 +#undef op0 +#undef op1 +#undef op2 + +#endif diff --git a/snes/chip/superfx/disasm/disasm.hpp b/snes/chip/superfx/disasm/disasm.hpp new file mode 100755 index 00000000..903615eb --- /dev/null +++ b/snes/chip/superfx/disasm/disasm.hpp @@ -0,0 +1,5 @@ +void disassemble_opcode(char *output); +void disassemble_alt0(char *output); +void disassemble_alt1(char *output); +void disassemble_alt2(char *output); +void disassemble_alt3(char *output); diff --git a/snes/chip/superfx/memory/memory.cpp b/snes/chip/superfx/memory/memory.cpp new file mode 100755 index 00000000..06b62db4 --- /dev/null +++ b/snes/chip/superfx/memory/memory.cpp @@ -0,0 +1,110 @@ +#ifdef SUPERFX_CPP + +uint8 SuperFX::bus_read(unsigned addr) { + if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff, $00-3f:8000-ffff + while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) { + add_clocks(6); + synchronize_cpu(); + } + return cartridge.rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & rom_mask); + } + + if((addr & 0xe00000) == 0x400000) { //$40-5f:0000-ffff + while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) { + add_clocks(6); + synchronize_cpu(); + } + return cartridge.rom.read(addr & rom_mask); + } + + if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff + while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) { + add_clocks(6); + synchronize_cpu(); + } + return cartridge.ram.read(addr & ram_mask); + } +} + +void SuperFX::bus_write(unsigned addr, uint8 data) { + if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff + while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) { + add_clocks(6); + synchronize_cpu(); + } + return cartridge.ram.write(addr & ram_mask, data); + } +} + +uint8 SuperFX::op_read(uint16 addr) { + uint16 offset = addr - regs.cbr; + if(offset < 512) { + if(cache.valid[offset >> 4] == false) { + unsigned dp = offset & 0xfff0; + unsigned sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0); + for(unsigned n = 0; n < 16; n++) { + add_clocks(memory_access_speed); + cache.buffer[dp++] = bus_read(sp++); + } + cache.valid[offset >> 4] = true; + } else { + add_clocks(cache_access_speed); + } + return cache.buffer[offset]; + } + + if(regs.pbr <= 0x5f) { + //$[00-5f]:[0000-ffff] ROM + rombuffer_sync(); + add_clocks(memory_access_speed); + return bus_read((regs.pbr << 16) + addr); + } else { + //$[60-7f]:[0000-ffff] RAM + rambuffer_sync(); + add_clocks(memory_access_speed); + return bus_read((regs.pbr << 16) + addr); + } +} + +uint8 SuperFX::peekpipe() { + uint8 result = regs.pipeline; + regs.pipeline = op_read(regs.r[15]); + r15_modified = false; + return result; +} + +uint8 SuperFX::pipe() { + uint8 result = regs.pipeline; + regs.pipeline = op_read(++regs.r[15]); + r15_modified = false; + return result; +} + +void SuperFX::cache_flush() { + for(unsigned n = 0; n < 32; n++) cache.valid[n] = false; +} + +uint8 SuperFX::cache_mmio_read(uint16 addr) { + addr = (addr + regs.cbr) & 511; + return cache.buffer[addr]; +} + +void SuperFX::cache_mmio_write(uint16 addr, uint8 data) { + addr = (addr + regs.cbr) & 511; + cache.buffer[addr] = data; + if((addr & 15) == 15) cache.valid[addr >> 4] = true; +} + +void SuperFX::memory_reset() { + rom_mask = cartridge.rom.size() - 1; + ram_mask = cartridge.ram.size() - 1; + + for(unsigned n = 0; n < 512; n++) cache.buffer[n] = 0x00; + for(unsigned n = 0; n < 32; n++) cache.valid[n] = false; + for(unsigned n = 0; n < 2; n++) { + pixelcache[n].offset = ~0; + pixelcache[n].bitpend = 0x00; + } +} + +#endif diff --git a/snes/chip/superfx/memory/memory.hpp b/snes/chip/superfx/memory/memory.hpp new file mode 100755 index 00000000..2ff62857 --- /dev/null +++ b/snes/chip/superfx/memory/memory.hpp @@ -0,0 +1,14 @@ +unsigned rom_mask; //rom_size - 1 +unsigned ram_mask; //ram_size - 1 +uint8 bus_read(unsigned addr); +void bus_write(unsigned addr, uint8 data); + +uint8 op_read(uint16 addr); +alwaysinline uint8 peekpipe(); +alwaysinline uint8 pipe(); + +void cache_flush(); +uint8 cache_mmio_read(uint16 addr); +void cache_mmio_write(uint16 addr, uint8 data); + +void memory_reset(); diff --git a/snes/chip/superfx/mmio/mmio.cpp b/snes/chip/superfx/mmio/mmio.cpp new file mode 100755 index 00000000..5650a77a --- /dev/null +++ b/snes/chip/superfx/mmio/mmio.cpp @@ -0,0 +1,118 @@ +#ifdef SUPERFX_CPP + +uint8 SuperFX::mmio_read(unsigned addr) { + cpu.synchronize_coprocessors(); + addr &= 0xffff; + + if(addr >= 0x3100 && addr <= 0x32ff) { + return cache_mmio_read(addr - 0x3100); + } + + if(addr >= 0x3000 && addr <= 0x301f) { + return regs.r[(addr >> 1) & 15] >> ((addr & 1) << 3); + } + + switch(addr) { + case 0x3030: { + return regs.sfr >> 0; + } + + case 0x3031: { + uint8 r = regs.sfr >> 8; + regs.sfr.irq = 0; + cpu.regs.irq = 0; + return r; + } + + case 0x3034: { + return regs.pbr; + } + + case 0x3036: { + return regs.rombr; + } + + case 0x303b: { + return regs.vcr; + } + + case 0x303c: { + return regs.rambr; + } + + case 0x303e: { + return regs.cbr >> 0; + } + + case 0x303f: { + return regs.cbr >> 8; + } + } + + return 0x00; +} + +void SuperFX::mmio_write(unsigned addr, uint8 data) { + cpu.synchronize_coprocessors(); + addr &= 0xffff; + + if(addr >= 0x3100 && addr <= 0x32ff) { + return cache_mmio_write(addr - 0x3100, data); + } + + if(addr >= 0x3000 && addr <= 0x301f) { + unsigned n = (addr >> 1) & 15; + if((addr & 1) == 0) { + regs.r[n] = (regs.r[n] & 0xff00) | data; + } else { + regs.r[n] = (data << 8) | (regs.r[n] & 0xff); + } + + if(addr == 0x301f) regs.sfr.g = 1; + return; + } + + switch(addr) { + case 0x3030: { + bool g = regs.sfr.g; + regs.sfr = (regs.sfr & 0xff00) | (data << 0); + if(g == 1 && regs.sfr.g == 0) { + regs.cbr = 0x0000; + cache_flush(); + } + } break; + + case 0x3031: { + regs.sfr = (data << 8) | (regs.sfr & 0x00ff); + } break; + + case 0x3033: { + regs.bramr = data; + } break; + + case 0x3034: { + regs.pbr = data & 0x7f; + cache_flush(); + } break; + + case 0x3037: { + regs.cfgr = data; + update_speed(); + } break; + + case 0x3038: { + regs.scbr = data; + } break; + + case 0x3039: { + regs.clsr = data; + update_speed(); + } break; + + case 0x303a: { + regs.scmr = data; + } break; + } +} + +#endif diff --git a/snes/chip/superfx/mmio/mmio.hpp b/snes/chip/superfx/mmio/mmio.hpp new file mode 100755 index 00000000..08cc85a9 --- /dev/null +++ b/snes/chip/superfx/mmio/mmio.hpp @@ -0,0 +1,2 @@ +uint8 mmio_read(unsigned addr); +void mmio_write(unsigned addr, uint8 data); diff --git a/snes/chip/superfx/serialization.cpp b/snes/chip/superfx/serialization.cpp new file mode 100755 index 00000000..67e5385b --- /dev/null +++ b/snes/chip/superfx/serialization.cpp @@ -0,0 +1,96 @@ +#ifdef SUPERFX_CPP + +void SuperFX::serialize(serializer &s) { + Processor::serialize(s); + + //superfx.hpp + s.integer(clockmode); + s.integer(instruction_counter); + + //core/registers.hpp + s.integer(regs.pipeline); + s.integer(regs.ramaddr); + + s.integer(regs.r[ 0].data); + s.integer(regs.r[ 1].data); + s.integer(regs.r[ 2].data); + s.integer(regs.r[ 3].data); + s.integer(regs.r[ 4].data); + s.integer(regs.r[ 5].data); + s.integer(regs.r[ 6].data); + s.integer(regs.r[ 7].data); + s.integer(regs.r[ 8].data); + s.integer(regs.r[ 9].data); + s.integer(regs.r[10].data); + s.integer(regs.r[11].data); + s.integer(regs.r[12].data); + s.integer(regs.r[13].data); + s.integer(regs.r[14].data); + s.integer(regs.r[15].data); + + s.integer(regs.sfr.irq); + s.integer(regs.sfr.b); + s.integer(regs.sfr.ih); + s.integer(regs.sfr.il); + s.integer(regs.sfr.alt2); + s.integer(regs.sfr.alt1); + s.integer(regs.sfr.r); + s.integer(regs.sfr.g); + s.integer(regs.sfr.ov); + s.integer(regs.sfr.s); + s.integer(regs.sfr.cy); + s.integer(regs.sfr.z); + + s.integer(regs.pbr); + s.integer(regs.rombr); + s.integer(regs.rambr); + s.integer(regs.cbr); + s.integer(regs.scbr); + + s.integer(regs.scmr.ht); + s.integer(regs.scmr.ron); + s.integer(regs.scmr.ran); + s.integer(regs.scmr.md); + + s.integer(regs.colr); + + s.integer(regs.por.obj); + s.integer(regs.por.freezehigh); + s.integer(regs.por.highnibble); + s.integer(regs.por.dither); + s.integer(regs.por.transparent); + + s.integer(regs.bramr); + s.integer(regs.vcr); + + s.integer(regs.cfgr.irq); + s.integer(regs.cfgr.ms0); + + s.integer(regs.clsr); + + s.integer(regs.romcl); + s.integer(regs.romdr); + + s.integer(regs.ramcl); + s.integer(regs.ramar); + s.integer(regs.ramdr); + + s.integer(regs.sreg); + s.integer(regs.dreg); + + s.array(cache.buffer); + s.array(cache.valid); + + for(unsigned i = 0; i < 2; i++) { + s.integer(pixelcache[i].offset); + s.integer(pixelcache[i].bitpend); + s.array(pixelcache[i].data); + } + + //timing/timing.hpp + s.integer(cache_access_speed); + s.integer(memory_access_speed); + s.integer(r15_modified); +} + +#endif diff --git a/snes/chip/superfx/superfx.cpp b/snes/chip/superfx/superfx.cpp new file mode 100755 index 00000000..fba0ff25 --- /dev/null +++ b/snes/chip/superfx/superfx.cpp @@ -0,0 +1,83 @@ +#include + +#define SUPERFX_CPP +namespace SNES { + +#include "serialization.cpp" +#include "bus/bus.cpp" +#include "core/core.cpp" +#include "memory/memory.cpp" +#include "mmio/mmio.cpp" +#include "timing/timing.cpp" +#include "disasm/disasm.cpp" + +SuperFX superfx; + +void SuperFX::Enter() { superfx.enter(); } + +void SuperFX::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(regs.sfr.g == 0) { + add_clocks(6); + synchronize_cpu(); + continue; + } + + (this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])(); + if(r15_modified == false) regs.r[15]++; + + if(++instruction_counter >= 128) { + instruction_counter = 0; + synchronize_cpu(); + } + } +} + +void SuperFX::init() { + initialize_opcode_table(); + regs.r[14].on_modify = { &SuperFX::r14_modify, this }; + regs.r[15].on_modify = { &SuperFX::r15_modify, this }; +} + +void SuperFX::load() { +} + +void SuperFX::unload() { +} + +void SuperFX::power() { + clockmode = config.superfx.speed; + reset(); +} + +void SuperFX::reset() { + create(SuperFX::Enter, system.cpu_frequency()); + instruction_counter = 0; + + for(unsigned n = 0; n < 16; n++) regs.r[n] = 0x0000; + regs.sfr = 0x0000; + regs.pbr = 0x00; + regs.rombr = 0x00; + regs.rambr = 0; + regs.cbr = 0x0000; + regs.scbr = 0x00; + regs.scmr = 0x00; + regs.colr = 0x00; + regs.por = 0x00; + regs.bramr = 0; + regs.vcr = 0x04; + regs.cfgr = 0x00; + regs.clsr = 0; + regs.pipeline = 0x01; //nop + regs.ramaddr = 0x0000; + regs.reset(); + + memory_reset(); + timing_reset(); +} + +} diff --git a/snes/chip/superfx/superfx.hpp b/snes/chip/superfx/superfx.hpp new file mode 100755 index 00000000..cf28952b --- /dev/null +++ b/snes/chip/superfx/superfx.hpp @@ -0,0 +1,24 @@ +class SuperFX : public Coprocessor { +public: + #include "bus/bus.hpp" + #include "core/core.hpp" + #include "memory/memory.hpp" + #include "mmio/mmio.hpp" + #include "timing/timing.hpp" + #include "disasm/disasm.hpp" + + static void Enter(); + void enter(); + void init(); + void load(); + void unload(); + void power(); + void reset(); + void serialize(serializer&); + +private: + unsigned clockmode; + unsigned instruction_counter; +}; + +extern SuperFX superfx; diff --git a/snes/chip/superfx/timing/timing.cpp b/snes/chip/superfx/timing/timing.cpp new file mode 100755 index 00000000..52765649 --- /dev/null +++ b/snes/chip/superfx/timing/timing.cpp @@ -0,0 +1,97 @@ +#ifdef SUPERFX_CPP + +void SuperFX::add_clocks(unsigned clocks) { + if(regs.romcl) { + regs.romcl -= min(clocks, regs.romcl); + if(regs.romcl == 0) { + regs.sfr.r = 0; + regs.romdr = bus_read((regs.rombr << 16) + regs.r[14]); + } + } + + if(regs.ramcl) { + regs.ramcl -= min(clocks, regs.ramcl); + if(regs.ramcl == 0) { + bus_write(0x700000 + (regs.rambr << 16) + regs.ramar, regs.ramdr); + } + } + + step(clocks); + synchronize_cpu(); +} + +void SuperFX::rombuffer_sync() { + if(regs.romcl) add_clocks(regs.romcl); +} + +void SuperFX::rombuffer_update() { + regs.sfr.r = 1; + regs.romcl = memory_access_speed; +} + +uint8 SuperFX::rombuffer_read() { + rombuffer_sync(); + return regs.romdr; +} + +void SuperFX::rambuffer_sync() { + if(regs.ramcl) add_clocks(regs.ramcl); +} + +uint8 SuperFX::rambuffer_read(uint16 addr) { + rambuffer_sync(); + return bus_read(0x700000 + (regs.rambr << 16) + addr); +} + +void SuperFX::rambuffer_write(uint16 addr, uint8 data) { + rambuffer_sync(); + regs.ramcl = memory_access_speed; + regs.ramar = addr; + regs.ramdr = data; +} + +void SuperFX::r14_modify(uint16 data) { + regs.r[14].data = data; + rombuffer_update(); +} + +void SuperFX::r15_modify(uint16 data) { + regs.r[15].data = data; + r15_modified = true; +} + +void SuperFX::update_speed() { + //force SuperFX1 mode? + if(clockmode == 1) { + cache_access_speed = 2; + memory_access_speed = 6; + return; + } + + //force SuperFX2 mode? + if(clockmode == 2) { + cache_access_speed = 1; + memory_access_speed = 5; + regs.cfgr.ms0 = 0; //cannot use high-speed multiplication in 21MHz mode + return; + } + + //default: allow S-CPU to select mode + cache_access_speed = (regs.clsr ? 1 : 2); + memory_access_speed = (regs.clsr ? 5 : 6); + if(regs.clsr) regs.cfgr.ms0 = 0; //cannot use high-speed multiplication in 21MHz mode +} + +void SuperFX::timing_reset() { + update_speed(); + r15_modified = false; + + regs.romcl = 0; + regs.romdr = 0; + + regs.ramcl = 0; + regs.ramar = 0; + regs.ramdr = 0; +} + +#endif diff --git a/snes/chip/superfx/timing/timing.hpp b/snes/chip/superfx/timing/timing.hpp new file mode 100755 index 00000000..9ae7e8d4 --- /dev/null +++ b/snes/chip/superfx/timing/timing.hpp @@ -0,0 +1,19 @@ +unsigned cache_access_speed; +unsigned memory_access_speed; +bool r15_modified; + +void add_clocks(unsigned clocks); + +void rombuffer_sync(); +void rombuffer_update(); +uint8 rombuffer_read(); + +void rambuffer_sync(); +uint8 rambuffer_read(uint16 addr); +void rambuffer_write(uint16 addr, uint8 data); + +void r14_modify(uint16); +void r15_modify(uint16); + +void update_speed(); +void timing_reset(); diff --git a/snes/config/config.cpp b/snes/config/config.cpp new file mode 100755 index 00000000..701af94c --- /dev/null +++ b/snes/config/config.cpp @@ -0,0 +1,26 @@ +#ifdef SYSTEM_CPP + +Configuration config; + +Configuration::Configuration() { + controller_port1 = Input::Device::Joypad; + controller_port2 = Input::Device::Joypad; + expansion_port = System::ExpansionPortDevice::BSX; + region = System::Region::Autodetect; + random = true; + + cpu.version = 2; + cpu.ntsc_frequency = 21477272; //315 / 88 * 6000000 + cpu.pal_frequency = 21281370; + cpu.wram_init_value = 0x55; + + smp.ntsc_frequency = 24607104; //32040.5 * 768 + smp.pal_frequency = 24607104; + + ppu1.version = 1; + ppu2.version = 3; + + superfx.speed = 0; //0 = auto-select, 1 = force 10.74MHz, 2 = force 21.48MHz +} + +#endif diff --git a/snes/config/config.hpp b/snes/config/config.hpp new file mode 100755 index 00000000..1f4d037c --- /dev/null +++ b/snes/config/config.hpp @@ -0,0 +1,35 @@ +struct Configuration { + Input::Device controller_port1; + Input::Device controller_port2; + System::ExpansionPortDevice expansion_port; + System::Region region; + bool random; + + struct CPU { + unsigned version; + unsigned ntsc_frequency; + unsigned pal_frequency; + unsigned wram_init_value; + } cpu; + + struct SMP { + unsigned ntsc_frequency; + unsigned pal_frequency; + } smp; + + struct PPU1 { + unsigned version; + } ppu1; + + struct PPU2 { + unsigned version; + } ppu2; + + struct SuperFX { + unsigned speed; + } superfx; + + Configuration(); +}; + +extern Configuration config; diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp new file mode 100755 index 00000000..9091b21b --- /dev/null +++ b/snes/controller/controller.cpp @@ -0,0 +1,53 @@ +#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 != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +} + +bool Controller::iobit() { + switch(port) { + case Controller::Port1: return cpu.pio() & 0x40; + case Controller::Port2: return cpu.pio() & 0x80; + } +} + +void Controller::iobit(bool data) { + switch(port) { + 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 100755 index 00000000..73327129 --- /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 : bool { 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 100755 index 00000000..594020d2 --- /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 = interface->inputPoll(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 100755 index 00000000..c5ca69ca --- /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 100755 index 00000000..8b2d3ee4 --- /dev/null +++ b/snes/controller/justifier/justifier.cpp @@ -0,0 +1,131 @@ +#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 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X); + int ny1 = interface->inputPoll(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 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X); + int ny2 = interface->inputPoll(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 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger); + start1 = interface->inputPoll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start); + if(chained) { + trigger2 = interface->inputPoll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger); + start2 = interface->inputPoll(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; + } +} + +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 100755 index 00000000..82591471 --- /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 100755 index 00000000..c9f5d16b --- /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 = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right + int position_y = interface->inputPoll(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 interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right); + case 9: return interface->inputPoll(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 100755 index 00000000..95e24b65 --- /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 100755 index 00000000..3a6eb720 --- /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 = interface->inputPoll(port, Input::Device::Multitap, port1, index); + bool data2 = interface->inputPoll(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 100755 index 00000000..0540af71 --- /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 100755 index 00000000..24491146 --- /dev/null +++ b/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 = 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/snes/controller/serial/serial.hpp b/snes/controller/serial/serial.hpp new file mode 100755 index 00000000..2a68ba53 --- /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 100755 index 00000000..e97a2ff5 --- /dev/null +++ b/snes/controller/superscope/superscope.cpp @@ -0,0 +1,127 @@ +#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 = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X); + int ny = interface->inputPoll(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 = interface->inputPoll(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 = interface->inputPoll(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 = interface->inputPoll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor); + + //pause is a button; it is always edge sensitive + pause = false; + bool newpause = interface->inputPoll(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) + } +} + +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 100755 index 00000000..a7a90b71 --- /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/core/algorithms.cpp b/snes/cpu/core/algorithms.cpp new file mode 100755 index 00000000..9b6ba032 --- /dev/null +++ b/snes/cpu/core/algorithms.cpp @@ -0,0 +1,331 @@ +#ifdef CPUCORE_CPP + +inline void CPUcore::op_adc_b() { + int result; + + if(!regs.p.d) { + result = regs.a.l + rd.l + regs.p.c; + } else { + result = (regs.a.l & 0x0f) + (rd.l & 0x0f) + (regs.p.c << 0); + if(result > 0x09) result += 0x06; + regs.p.c = result > 0x0f; + result = (regs.a.l & 0xf0) + (rd.l & 0xf0) + (regs.p.c << 4) + (result & 0x0f); + } + + regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ result) & 0x80; + if(regs.p.d && result > 0x9f) result += 0x60; + regs.p.c = result > 0xff; + regs.p.n = result & 0x80; + regs.p.z = (uint8_t)result == 0; + + regs.a.l = result; +} + +inline void CPUcore::op_adc_w() { + int result; + + if(!regs.p.d) { + result = regs.a.w + rd.w + regs.p.c; + } else { + result = (regs.a.w & 0x000f) + (rd.w & 0x000f) + (regs.p.c << 0); + if(result > 0x0009) result += 0x0006; + regs.p.c = result > 0x000f; + result = (regs.a.w & 0x00f0) + (rd.w & 0x00f0) + (regs.p.c << 4) + (result & 0x000f); + if(result > 0x009f) result += 0x0060; + regs.p.c = result > 0x00ff; + result = (regs.a.w & 0x0f00) + (rd.w & 0x0f00) + (regs.p.c << 8) + (result & 0x00ff); + if(result > 0x09ff) result += 0x0600; + regs.p.c = result > 0x0fff; + result = (regs.a.w & 0xf000) + (rd.w & 0xf000) + (regs.p.c << 12) + (result & 0x0fff); + } + + regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ result) & 0x8000; + if(regs.p.d && result > 0x9fff) result += 0x6000; + regs.p.c = result > 0xffff; + regs.p.n = result & 0x8000; + regs.p.z = (uint16_t)result == 0; + + regs.a.w = result; +} + +inline void CPUcore::op_and_b() { + regs.a.l &= rd.l; + regs.p.n = regs.a.l & 0x80; + regs.p.z = regs.a.l == 0; +} + +inline void CPUcore::op_and_w() { + regs.a.w &= rd.w; + regs.p.n = regs.a.w & 0x8000; + regs.p.z = regs.a.w == 0; +} + +inline void CPUcore::op_bit_b() { + regs.p.n = rd.l & 0x80; + regs.p.v = rd.l & 0x40; + regs.p.z = (rd.l & regs.a.l) == 0; +} + +inline void CPUcore::op_bit_w() { + regs.p.n = rd.w & 0x8000; + regs.p.v = rd.w & 0x4000; + regs.p.z = (rd.w & regs.a.w) == 0; +} + +inline void CPUcore::op_cmp_b() { + int r = regs.a.l - rd.l; + regs.p.n = r & 0x80; + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; +} + +inline void CPUcore::op_cmp_w() { + int r = regs.a.w - rd.w; + regs.p.n = r & 0x8000; + regs.p.z = (uint16)r == 0; + regs.p.c = r >= 0; +} + +inline void CPUcore::op_cpx_b() { + int r = regs.x.l - rd.l; + regs.p.n = r & 0x80; + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; +} + +inline void CPUcore::op_cpx_w() { + int r = regs.x.w - rd.w; + regs.p.n = r & 0x8000; + regs.p.z = (uint16)r == 0; + regs.p.c = r >= 0; +} + +inline void CPUcore::op_cpy_b() { + int r = regs.y.l - rd.l; + regs.p.n = r & 0x80; + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; +} + +inline void CPUcore::op_cpy_w() { + int r = regs.y.w - rd.w; + regs.p.n = r & 0x8000; + regs.p.z = (uint16)r == 0; + regs.p.c = r >= 0; +} + +inline void CPUcore::op_eor_b() { + regs.a.l ^= rd.l; + regs.p.n = regs.a.l & 0x80; + regs.p.z = regs.a.l == 0; +} + +inline void CPUcore::op_eor_w() { + regs.a.w ^= rd.w; + regs.p.n = regs.a.w & 0x8000; + regs.p.z = regs.a.w == 0; +} + +inline void CPUcore::op_lda_b() { + regs.a.l = rd.l; + regs.p.n = regs.a.l & 0x80; + regs.p.z = regs.a.l == 0; +} + +inline void CPUcore::op_lda_w() { + regs.a.w = rd.w; + regs.p.n = regs.a.w & 0x8000; + regs.p.z = regs.a.w == 0; +} + +inline void CPUcore::op_ldx_b() { + regs.x.l = rd.l; + regs.p.n = regs.x.l & 0x80; + regs.p.z = regs.x.l == 0; +} + +inline void CPUcore::op_ldx_w() { + regs.x.w = rd.w; + regs.p.n = regs.x.w & 0x8000; + regs.p.z = regs.x.w == 0; +} + +inline void CPUcore::op_ldy_b() { + regs.y.l = rd.l; + regs.p.n = regs.y.l & 0x80; + regs.p.z = regs.y.l == 0; +} + +inline void CPUcore::op_ldy_w() { + regs.y.w = rd.w; + regs.p.n = regs.y.w & 0x8000; + regs.p.z = regs.y.w == 0; +} + +inline void CPUcore::op_ora_b() { + regs.a.l |= rd.l; + regs.p.n = regs.a.l & 0x80; + regs.p.z = regs.a.l == 0; +} + +inline void CPUcore::op_ora_w() { + regs.a.w |= rd.w; + regs.p.n = regs.a.w & 0x8000; + regs.p.z = regs.a.w == 0; +} + +inline void CPUcore::op_sbc_b() { + int result; + rd.l ^= 0xff; + + if(!regs.p.d) { + result = regs.a.l + rd.l + regs.p.c; + } else { + result = (regs.a.l & 0x0f) + (rd.l & 0x0f) + (regs.p.c << 0); + if(result <= 0x0f) result -= 0x06; + regs.p.c = result > 0x0f; + result = (regs.a.l & 0xf0) + (rd.l & 0xf0) + (regs.p.c << 4) + (result & 0x0f); + } + + regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ result) & 0x80; + if(regs.p.d && result <= 0xff) result -= 0x60; + regs.p.c = result > 0xff; + regs.p.n = result & 0x80; + regs.p.z = (uint8_t)result == 0; + + regs.a.l = result; +} + +inline void CPUcore::op_sbc_w() { + int result; + rd.w ^= 0xffff; + + if(!regs.p.d) { + result = regs.a.w + rd.w + regs.p.c; + } else { + result = (regs.a.w & 0x000f) + (rd.w & 0x000f) + (regs.p.c << 0); + if(result <= 0x000f) result -= 0x0006; + regs.p.c = result > 0x000f; + result = (regs.a.w & 0x00f0) + (rd.w & 0x00f0) + (regs.p.c << 4) + (result & 0x000f); + if(result <= 0x00ff) result -= 0x0060; + regs.p.c = result > 0x00ff; + result = (regs.a.w & 0x0f00) + (rd.w & 0x0f00) + (regs.p.c << 8) + (result & 0x00ff); + if(result <= 0x0fff) result -= 0x0600; + regs.p.c = result > 0x0fff; + result = (regs.a.w & 0xf000) + (rd.w & 0xf000) + (regs.p.c << 12) + (result & 0x0fff); + } + + regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ result) & 0x8000; + if(regs.p.d && result <= 0xffff) result -= 0x6000; + regs.p.c = result > 0xffff; + regs.p.n = result & 0x8000; + regs.p.z = (uint16_t)result == 0; + + regs.a.w = result; +} + +inline void CPUcore::op_inc_b() { + rd.l++; + regs.p.n = rd.l & 0x80; + regs.p.z = rd.l == 0; +} + +inline void CPUcore::op_inc_w() { + rd.w++; + regs.p.n = rd.w & 0x8000; + regs.p.z = rd.w == 0; +} + +inline void CPUcore::op_dec_b() { + rd.l--; + regs.p.n = rd.l & 0x80; + regs.p.z = rd.l == 0; +} + +inline void CPUcore::op_dec_w() { + rd.w--; + regs.p.n = rd.w & 0x8000; + regs.p.z = rd.w == 0; +} + +inline void CPUcore::op_asl_b() { + regs.p.c = rd.l & 0x80; + rd.l <<= 1; + regs.p.n = rd.l & 0x80; + regs.p.z = rd.l == 0; +} + +inline void CPUcore::op_asl_w() { + regs.p.c = rd.w & 0x8000; + rd.w <<= 1; + regs.p.n = rd.w & 0x8000; + regs.p.z = rd.w == 0; +} + +inline void CPUcore::op_lsr_b() { + regs.p.c = rd.l & 1; + rd.l >>= 1; + regs.p.n = rd.l & 0x80; + regs.p.z = rd.l == 0; +} + +inline void CPUcore::op_lsr_w() { + regs.p.c = rd.w & 1; + rd.w >>= 1; + regs.p.n = rd.w & 0x8000; + regs.p.z = rd.w == 0; +} + +inline void CPUcore::op_rol_b() { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = rd.l & 0x80; + rd.l = (rd.l << 1) | carry; + regs.p.n = rd.l & 0x80; + regs.p.z = rd.l == 0; +} + +inline void CPUcore::op_rol_w() { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = rd.w & 0x8000; + rd.w = (rd.w << 1) | carry; + regs.p.n = rd.w & 0x8000; + regs.p.z = rd.w == 0; +} + +inline void CPUcore::op_ror_b() { + unsigned carry = (unsigned)regs.p.c << 7; + regs.p.c = rd.l & 1; + rd.l = carry | (rd.l >> 1); + regs.p.n = rd.l & 0x80; + regs.p.z = rd.l == 0; +} + +inline void CPUcore::op_ror_w() { + unsigned carry = (unsigned)regs.p.c << 15; + regs.p.c = rd.w & 1; + rd.w = carry | (rd.w >> 1); + regs.p.n = rd.w & 0x8000; + regs.p.z = rd.w == 0; +} + +inline void CPUcore::op_trb_b() { + regs.p.z = (rd.l & regs.a.l) == 0; + rd.l &= ~regs.a.l; +} + +inline void CPUcore::op_trb_w() { + regs.p.z = (rd.w & regs.a.w) == 0; + rd.w &= ~regs.a.w; +} + +inline void CPUcore::op_tsb_b() { + regs.p.z = (rd.l & regs.a.l) == 0; + rd.l |= regs.a.l; +} + +inline void CPUcore::op_tsb_w() { + regs.p.z = (rd.w & regs.a.w) == 0; + rd.w |= regs.a.w; +} + +#endif diff --git a/snes/cpu/core/core.cpp b/snes/cpu/core/core.cpp new file mode 100755 index 00000000..427176b0 --- /dev/null +++ b/snes/cpu/core/core.cpp @@ -0,0 +1,89 @@ +#include + +#define CPUCORE_CPP +namespace SNES { + +#include "serialization.cpp" +#include "algorithms.cpp" +#include "disassembler/disassembler.cpp" + +#define L last_cycle(); +#define A 0 +#define X 1 +#define Y 2 +#define Z 3 +#define S 4 +#define D 5 +#define call(op) (this->*op)() + +#include "opcode_read.cpp" +#include "opcode_write.cpp" +#include "opcode_rmw.cpp" +#include "opcode_pc.cpp" +#include "opcode_misc.cpp" +#include "table.cpp" + +#undef L +#undef A +#undef X +#undef Y +#undef Z +#undef S +#undef D +#undef call + +//immediate, 2-cycle opcodes with I/O cycle will become bus read +//when an IRQ is to be triggered immediately after opcode completion. +//this affects the following opcodes: +// clc, cld, cli, clv, sec, sed, sei, +// tax, tay, txa, txy, tya, tyx, +// tcd, tcs, tdc, tsc, tsx, txs, +// inc, inx, iny, dec, dex, dey, +// asl, lsr, rol, ror, nop, xce. +alwaysinline void CPUcore::op_io_irq() { + if(interrupt_pending()) { + //modify I/O cycle to bus read cycle, do not increment PC + op_read(regs.pc.d); + } else { + op_io(); + } +} + +alwaysinline void CPUcore::op_io_cond2() { + if(regs.d.l != 0x00) { + op_io(); + } +} + +alwaysinline void CPUcore::op_io_cond4(uint16 x, uint16 y) { + if(!regs.p.x || (x & 0xff00) != (y & 0xff00)) { + op_io(); + } +} + +alwaysinline void CPUcore::op_io_cond6(uint16 addr) { + if(regs.e && (regs.pc.w & 0xff00) != (addr & 0xff00)) { + op_io(); + } +} + +void CPUcore::op_irq() { + op_read(regs.pc.d); + op_io(); + if(!regs.e) op_writestack(regs.pc.b); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + op_writestack(regs.e ? (regs.p & ~0x10) : regs.p); + rd.l = op_read(regs.vector + 0); + regs.pc.b = 0x00; + regs.p.i = 1; + regs.p.d = 0; + rd.h = op_read(regs.vector + 1); + regs.pc.w = rd.w; +} + +CPUcore::CPUcore() { + initialize_opcode_table(); +} + +} diff --git a/snes/cpu/core/core.hpp b/snes/cpu/core/core.hpp new file mode 100755 index 00000000..964bd128 --- /dev/null +++ b/snes/cpu/core/core.hpp @@ -0,0 +1,217 @@ +struct CPUcore { + #include "registers.hpp" + #include "memory.hpp" + #include "disassembler/disassembler.hpp" + + regs_t regs; + reg24_t aa, rd; + uint8_t sp, dp; + + virtual void op_io() = 0; + virtual uint8_t op_read(uint32_t addr) = 0; + virtual void op_write(uint32_t addr, uint8_t data) = 0; + virtual void last_cycle() = 0; + virtual bool interrupt_pending() = 0; + virtual void op_irq(); + + void op_io_irq(); + void op_io_cond2(); + void op_io_cond4(uint16 x, uint16 y); + void op_io_cond6(uint16 addr); + + void op_adc_b(); + void op_adc_w(); + void op_and_b(); + void op_and_w(); + void op_bit_b(); + void op_bit_w(); + void op_cmp_b(); + void op_cmp_w(); + void op_cpx_b(); + void op_cpx_w(); + void op_cpy_b(); + void op_cpy_w(); + void op_eor_b(); + void op_eor_w(); + void op_lda_b(); + void op_lda_w(); + void op_ldx_b(); + void op_ldx_w(); + void op_ldy_b(); + void op_ldy_w(); + void op_ora_b(); + void op_ora_w(); + void op_sbc_b(); + void op_sbc_w(); + + void op_inc_b(); + void op_inc_w(); + void op_dec_b(); + void op_dec_w(); + void op_asl_b(); + void op_asl_w(); + void op_lsr_b(); + void op_lsr_w(); + void op_rol_b(); + void op_rol_w(); + void op_ror_b(); + void op_ror_w(); + void op_trb_b(); + void op_trb_w(); + void op_tsb_b(); + void op_tsb_w(); + + template void op_read_const_b(); + template void op_read_const_w(); + void op_read_bit_const_b(); + void op_read_bit_const_w(); + template void op_read_addr_b(); + template void op_read_addr_w(); + template void op_read_addrx_b(); + template void op_read_addrx_w(); + template void op_read_addry_b(); + template void op_read_addry_w(); + template void op_read_long_b(); + template void op_read_long_w(); + template void op_read_longx_b(); + template void op_read_longx_w(); + template void op_read_dp_b(); + template void op_read_dp_w(); + template void op_read_dpr_b(); + template void op_read_dpr_w(); + template void op_read_idp_b(); + template void op_read_idp_w(); + template void op_read_idpx_b(); + template void op_read_idpx_w(); + template void op_read_idpy_b(); + template void op_read_idpy_w(); + template void op_read_ildp_b(); + template void op_read_ildp_w(); + template void op_read_ildpy_b(); + template void op_read_ildpy_w(); + template void op_read_sr_b(); + template void op_read_sr_w(); + template void op_read_isry_b(); + template void op_read_isry_w(); + + template void op_write_addr_b(); + template void op_write_addr_w(); + template void op_write_addrr_b(); + template void op_write_addrr_w(); + template void op_write_longr_b(); + template void op_write_longr_w(); + template void op_write_dp_b(); + template void op_write_dp_w(); + template void op_write_dpr_b(); + template void op_write_dpr_w(); + void op_sta_idp_b(); + void op_sta_idp_w(); + void op_sta_ildp_b(); + void op_sta_ildp_w(); + void op_sta_idpx_b(); + void op_sta_idpx_w(); + void op_sta_idpy_b(); + void op_sta_idpy_w(); + void op_sta_ildpy_b(); + void op_sta_ildpy_w(); + void op_sta_sr_b(); + void op_sta_sr_w(); + void op_sta_isry_b(); + void op_sta_isry_w(); + + template void op_adjust_imm_b(); + template void op_adjust_imm_w(); + void op_asl_imm_b(); + void op_asl_imm_w(); + void op_lsr_imm_b(); + void op_lsr_imm_w(); + void op_rol_imm_b(); + void op_rol_imm_w(); + void op_ror_imm_b(); + void op_ror_imm_w(); + template void op_adjust_addr_b(); + template void op_adjust_addr_w(); + template void op_adjust_addrx_b(); + template void op_adjust_addrx_w(); + template void op_adjust_dp_b(); + template void op_adjust_dp_w(); + template void op_adjust_dpx_b(); + template void op_adjust_dpx_w(); + + template void op_branch(); + void op_bra(); + void op_brl(); + void op_jmp_addr(); + void op_jmp_long(); + void op_jmp_iaddr(); + void op_jmp_iaddrx(); + void op_jmp_iladdr(); + void op_jsr_addr(); + void op_jsr_long_e(); + void op_jsr_long_n(); + void op_jsr_iaddrx_e(); + void op_jsr_iaddrx_n(); + void op_rti_e(); + void op_rti_n(); + void op_rts(); + void op_rtl_e(); + void op_rtl_n(); + + void op_nop(); + void op_wdm(); + void op_xba(); + template void op_move_b(); + template void op_move_w(); + template void op_interrupt_e(); + template void op_interrupt_n(); + void op_stp(); + void op_wai(); + void op_xce(); + template void op_flag(); + template void op_pflag_e(); + template void op_pflag_n(); + template void op_transfer_b(); + template void op_transfer_w(); + void op_tcs_e(); + void op_tcs_n(); + void op_tsx_b(); + void op_tsx_w(); + void op_txs_e(); + void op_txs_n(); + template void op_push_b(); + template void op_push_w(); + void op_phd_e(); + void op_phd_n(); + void op_phb(); + void op_phk(); + void op_php(); + template void op_pull_b(); + template void op_pull_w(); + void op_pld_e(); + void op_pld_n(); + void op_plb(); + void op_plp_e(); + void op_plp_n(); + void op_pea_e(); + void op_pea_n(); + void op_pei_e(); + void op_pei_n(); + void op_per_e(); + void op_per_n(); + + void (CPUcore::**opcode_table)(); + void (CPUcore::*op_table[256 * 5])(); + void initialize_opcode_table(); + void update_table(); + + enum { + table_EM = 0, // 8-bit accumulator, 8-bit index (emulation mode) + table_MX = 256, // 8-bit accumulator, 8-bit index + table_Mx = 512, // 8-bit accumulator, 16-bit index + table_mX = 768, //16-bit accumulator, 8-bit index + table_mx = 1024, //16-bit accumulator, 16-bit index + }; + + void core_serialize(serializer&); + CPUcore(); +}; diff --git a/snes/cpu/core/disassembler/disassembler.cpp b/snes/cpu/core/disassembler/disassembler.cpp new file mode 100755 index 00000000..030b3ab5 --- /dev/null +++ b/snes/cpu/core/disassembler/disassembler.cpp @@ -0,0 +1,483 @@ +#ifdef CPUCORE_CPP + +uint8 CPUcore::dreadb(uint32 addr) { + if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) { + //$[00-3f|80-bf]:[2000-5fff] + //do not read MMIO registers within debugger + return 0x00; + } + return bus.read(addr); +} + +uint16 CPUcore::dreadw(uint32 addr) { + uint16 r; + r = dreadb((addr + 0) & 0xffffff) << 0; + r |= dreadb((addr + 1) & 0xffffff) << 8; + return r; +} + +uint32 CPUcore::dreadl(uint32 addr) { + uint32 r; + r = dreadb((addr + 0) & 0xffffff) << 0; + r |= dreadb((addr + 1) & 0xffffff) << 8; + r |= dreadb((addr + 2) & 0xffffff) << 16; + return r; +} + +uint32 CPUcore::decode(uint8 offset_type, uint32 addr) { + uint32 r = 0; + + switch(offset_type) { + case OPTYPE_DP: + r = (regs.d + (addr & 0xffff)) & 0xffff; + break; + case OPTYPE_DPX: + r = (regs.d + regs.x + (addr & 0xffff)) & 0xffff; + break; + case OPTYPE_DPY: + r = (regs.d + regs.y + (addr & 0xffff)) & 0xffff; + break; + case OPTYPE_IDP: + addr = (regs.d + (addr & 0xffff)) & 0xffff; + r = (regs.db << 16) + dreadw(addr); + break; + case OPTYPE_IDPX: + addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff; + r = (regs.db << 16) + dreadw(addr); + break; + case OPTYPE_IDPY: + addr = (regs.d + (addr & 0xffff)) & 0xffff; + r = (regs.db << 16) + dreadw(addr) + regs.y; + break; + case OPTYPE_ILDP: + addr = (regs.d + (addr & 0xffff)) & 0xffff; + r = dreadl(addr); + break; + case OPTYPE_ILDPY: + addr = (regs.d + (addr & 0xffff)) & 0xffff; + r = dreadl(addr) + regs.y; + break; + case OPTYPE_ADDR: + r = (regs.db << 16) + (addr & 0xffff); + break; + case OPTYPE_ADDR_PC: + r = (regs.pc.b << 16) + (addr & 0xffff); + break; + case OPTYPE_ADDRX: + r = (regs.db << 16) + (addr & 0xffff) + regs.x; + break; + case OPTYPE_ADDRY: + r = (regs.db << 16) + (addr & 0xffff) + regs.y; + break; + case OPTYPE_IADDR_PC: + r = (regs.pc.b << 16) + (addr & 0xffff); + break; + case OPTYPE_IADDRX: + r = (regs.pc.b << 16) + ((addr + regs.x) & 0xffff); + break; + case OPTYPE_ILADDR: + r = addr; + break; + case OPTYPE_LONG: + r = addr; + break; + case OPTYPE_LONGX: + r = (addr + regs.x); + break; + case OPTYPE_SR: + r = (regs.s + (addr & 0xff)) & 0xffff; + break; + case OPTYPE_ISRY: + addr = (regs.s + (addr & 0xff)) & 0xffff; + r = (regs.db << 16) + dreadw(addr) + regs.y; + break; + case OPTYPE_RELB: + r = (regs.pc.b << 16) + ((regs.pc.w + 2) & 0xffff); + r += int8(addr); + break; + case OPTYPE_RELW: + r = (regs.pc.b << 16) + ((regs.pc.w + 3) & 0xffff); + r += int16(addr); + break; + } + + return(r & 0xffffff); +} + +void CPUcore::disassemble_opcode(char *output, uint32 addr) { + static reg24_t pc; + char t[256]; + char *s = output; + + if(false /* in_opcode() == true */) { + strcpy(s, "?????? "); + return; + } + + pc.d = addr; + sprintf(s, "%.6x ", (uint32)pc.d); + + uint8 op = dreadb(pc.d); pc.w++; + uint8 op0 = dreadb(pc.d); pc.w++; + uint8 op1 = dreadb(pc.d); pc.w++; + uint8 op2 = dreadb(pc.d); + + #define op8 ((op0)) + #define op16 ((op0) | (op1 << 8)) + #define op24 ((op0) | (op1 << 8) | (op2 << 16)) + #define a8 (regs.e || regs.p.m) + #define x8 (regs.e || regs.p.x) + + switch(op) { + case 0x00: sprintf(t, "brk #$%.2x ", op8); break; + case 0x01: sprintf(t, "ora ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x02: sprintf(t, "cop #$%.2x ", op8); break; + case 0x03: sprintf(t, "ora $%.2x,s [%.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x04: sprintf(t, "tsb $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x05: sprintf(t, "ora $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x06: sprintf(t, "asl $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x07: sprintf(t, "ora [$%.2x] [%.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x08: sprintf(t, "php "); break; + case 0x09: if(a8)sprintf(t, "ora #$%.2x ", op8); + else sprintf(t, "ora #$%.4x ", op16); break; + case 0x0a: sprintf(t, "asl a "); break; + case 0x0b: sprintf(t, "phd "); break; + case 0x0c: sprintf(t, "tsb $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x0d: sprintf(t, "ora $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x0e: sprintf(t, "asl $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x0f: sprintf(t, "ora $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x10: sprintf(t, "bpl $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x11: sprintf(t, "ora ($%.2x),y [%.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x12: sprintf(t, "ora ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x13: sprintf(t, "ora ($%.2x,s),y [%.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x14: sprintf(t, "trb $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x15: sprintf(t, "ora $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x16: sprintf(t, "asl $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x17: sprintf(t, "ora [$%.2x],y [%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x18: sprintf(t, "clc "); break; + case 0x19: sprintf(t, "ora $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x1a: sprintf(t, "inc "); break; + case 0x1b: sprintf(t, "tcs "); break; + case 0x1c: sprintf(t, "trb $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x1d: sprintf(t, "ora $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x1e: sprintf(t, "asl $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x1f: sprintf(t, "ora $%.6x,x [%.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0x20: sprintf(t, "jsr $%.4x [%.6x]", op16, decode(OPTYPE_ADDR_PC, op16)); break; + case 0x21: sprintf(t, "and ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x22: sprintf(t, "jsl $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x23: sprintf(t, "and $%.2x,s [%.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x24: sprintf(t, "bit $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x25: sprintf(t, "and $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x26: sprintf(t, "rol $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x27: sprintf(t, "and [$%.2x] [%.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x28: sprintf(t, "plp "); break; + case 0x29: if(a8)sprintf(t, "and #$%.2x ", op8); + else sprintf(t, "and #$%.4x ", op16); break; + case 0x2a: sprintf(t, "rol a "); break; + case 0x2b: sprintf(t, "pld "); break; + case 0x2c: sprintf(t, "bit $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x2d: sprintf(t, "and $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x2e: sprintf(t, "rol $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x2f: sprintf(t, "and $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x30: sprintf(t, "bmi $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x31: sprintf(t, "and ($%.2x),y [%.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x32: sprintf(t, "and ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x33: sprintf(t, "and ($%.2x,s),y [%.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x34: sprintf(t, "bit $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x35: sprintf(t, "and $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x36: sprintf(t, "rol $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x37: sprintf(t, "and [$%.2x],y [%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x38: sprintf(t, "sec "); break; + case 0x39: sprintf(t, "and $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x3a: sprintf(t, "dec "); break; + case 0x3b: sprintf(t, "tsc "); break; + case 0x3c: sprintf(t, "bit $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x3d: sprintf(t, "and $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x3e: sprintf(t, "rol $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x3f: sprintf(t, "and $%.6x,x [%.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0x40: sprintf(t, "rti "); break; + case 0x41: sprintf(t, "eor ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x42: sprintf(t, "wdm "); break; + case 0x43: sprintf(t, "eor $%.2x,s [%.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x44: sprintf(t, "mvp $%.2x,$%.2x ", op1, op8); break; + case 0x45: sprintf(t, "eor $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x46: sprintf(t, "lsr $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x47: sprintf(t, "eor [$%.2x] [%.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x48: sprintf(t, "pha "); break; + case 0x49: if(a8)sprintf(t, "eor #$%.2x ", op8); + else sprintf(t, "eor #$%.4x ", op16); break; + case 0x4a: sprintf(t, "lsr a "); break; + case 0x4b: sprintf(t, "phk "); break; + case 0x4c: sprintf(t, "jmp $%.4x [%.6x]", op16, decode(OPTYPE_ADDR_PC, op16)); break; + case 0x4d: sprintf(t, "eor $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x4e: sprintf(t, "lsr $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x4f: sprintf(t, "eor $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x50: sprintf(t, "bvc $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x51: sprintf(t, "eor ($%.2x),y [%.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x52: sprintf(t, "eor ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x53: sprintf(t, "eor ($%.2x,s),y [%.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x54: sprintf(t, "mvn $%.2x,$%.2x ", op1, op8); break; + case 0x55: sprintf(t, "eor $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x56: sprintf(t, "lsr $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x57: sprintf(t, "eor [$%.2x],y [%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x58: sprintf(t, "cli "); break; + case 0x59: sprintf(t, "eor $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x5a: sprintf(t, "phy "); break; + case 0x5b: sprintf(t, "tcd "); break; + case 0x5c: sprintf(t, "jml $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x5d: sprintf(t, "eor $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x5e: sprintf(t, "lsr $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x5f: sprintf(t, "eor $%.6x,x [%.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0x60: sprintf(t, "rts "); break; + case 0x61: sprintf(t, "adc ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x62: sprintf(t, "per $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x63: sprintf(t, "adc $%.2x,s [%.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x64: sprintf(t, "stz $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x65: sprintf(t, "adc $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x66: sprintf(t, "ror $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x67: sprintf(t, "adc [$%.2x] [%.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x68: sprintf(t, "pla "); break; + case 0x69: if(a8)sprintf(t, "adc #$%.2x ", op8); + else sprintf(t, "adc #$%.4x ", op16); break; + case 0x6a: sprintf(t, "ror a "); break; + case 0x6b: sprintf(t, "rtl "); break; + case 0x6c: sprintf(t, "jmp ($%.4x) [%.6x]", op16, decode(OPTYPE_IADDR_PC, op16)); break; + case 0x6d: sprintf(t, "adc $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x6e: sprintf(t, "ror $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x6f: sprintf(t, "adc $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x70: sprintf(t, "bvs $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x71: sprintf(t, "adc ($%.2x),y [%.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x72: sprintf(t, "adc ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x73: sprintf(t, "adc ($%.2x,s),y [%.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x74: sprintf(t, "stz $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x75: sprintf(t, "adc $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x76: sprintf(t, "ror $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x77: sprintf(t, "adc [$%.2x],y [%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x78: sprintf(t, "sei "); break; + case 0x79: sprintf(t, "adc $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x7a: sprintf(t, "ply "); break; + case 0x7b: sprintf(t, "tdc "); break; + case 0x7c: sprintf(t, "jmp ($%.4x,x) [%.6x]", op16, decode(OPTYPE_IADDRX, op16)); break; + case 0x7d: sprintf(t, "adc $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x7e: sprintf(t, "ror $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x7f: sprintf(t, "adc $%.6x,x [%.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0x80: sprintf(t, "bra $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x81: sprintf(t, "sta ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0x82: sprintf(t, "brl $%.4x [%.6x]", uint16(decode(OPTYPE_RELW, op16)), decode(OPTYPE_RELW, op16)); break; + case 0x83: sprintf(t, "sta $%.2x,s [%.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0x84: sprintf(t, "sty $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x85: sprintf(t, "sta $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x86: sprintf(t, "stx $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0x87: sprintf(t, "sta [$%.2x] [%.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0x88: sprintf(t, "dey "); break; + case 0x89: if(a8)sprintf(t, "bit #$%.2x ", op8); + else sprintf(t, "bit #$%.4x ", op16); break; + case 0x8a: sprintf(t, "txa "); break; + case 0x8b: sprintf(t, "phb "); break; + case 0x8c: sprintf(t, "sty $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x8d: sprintf(t, "sta $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x8e: sprintf(t, "stx $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x8f: sprintf(t, "sta $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0x90: sprintf(t, "bcc $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0x91: sprintf(t, "sta ($%.2x),y [%.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0x92: sprintf(t, "sta ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0x93: sprintf(t, "sta ($%.2x,s),y [%.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0x94: sprintf(t, "sty $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x95: sprintf(t, "sta $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0x96: sprintf(t, "stx $%.2x,y [%.6x]", op8, decode(OPTYPE_DPY, op8)); break; + case 0x97: sprintf(t, "sta [$%.2x],y [%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0x98: sprintf(t, "tya "); break; + case 0x99: sprintf(t, "sta $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0x9a: sprintf(t, "txs "); break; + case 0x9b: sprintf(t, "txy "); break; + case 0x9c: sprintf(t, "stz $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0x9d: sprintf(t, "sta $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x9e: sprintf(t, "stz $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0x9f: sprintf(t, "sta $%.6x,x [%.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0xa0: if(x8)sprintf(t, "ldy #$%.2x ", op8); + else sprintf(t, "ldy #$%.4x ", op16); break; + case 0xa1: sprintf(t, "lda ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0xa2: if(x8)sprintf(t, "ldx #$%.2x ", op8); + else sprintf(t, "ldx #$%.4x ", op16); break; + case 0xa3: sprintf(t, "lda $%.2x,s [%.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0xa4: sprintf(t, "ldy $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xa5: sprintf(t, "lda $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xa6: sprintf(t, "ldx $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xa7: sprintf(t, "lda [$%.2x] [%.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0xa8: sprintf(t, "tay "); break; + case 0xa9: if(a8)sprintf(t, "lda #$%.2x ", op8); + else sprintf(t, "lda #$%.4x ", op16); break; + case 0xaa: sprintf(t, "tax "); break; + case 0xab: sprintf(t, "plb "); break; + case 0xac: sprintf(t, "ldy $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xad: sprintf(t, "lda $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xae: sprintf(t, "ldx $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xaf: sprintf(t, "lda $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0xb0: sprintf(t, "bcs $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0xb1: sprintf(t, "lda ($%.2x),y [%.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0xb2: sprintf(t, "lda ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0xb3: sprintf(t, "lda ($%.2x,s),y [%.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0xb4: sprintf(t, "ldy $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xb5: sprintf(t, "lda $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xb6: sprintf(t, "ldx $%.2x,y [%.6x]", op8, decode(OPTYPE_DPY, op8)); break; + case 0xb7: sprintf(t, "lda [$%.2x],y [%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0xb8: sprintf(t, "clv "); break; + case 0xb9: sprintf(t, "lda $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0xba: sprintf(t, "tsx "); break; + case 0xbb: sprintf(t, "tyx "); break; + case 0xbc: sprintf(t, "ldy $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xbd: sprintf(t, "lda $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xbe: sprintf(t, "ldx $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0xbf: sprintf(t, "lda $%.6x,x [%.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0xc0: if(x8)sprintf(t, "cpy #$%.2x ", op8); + else sprintf(t, "cpy #$%.4x ", op16); break; + case 0xc1: sprintf(t, "cmp ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0xc2: sprintf(t, "rep #$%.2x ", op8); break; + case 0xc3: sprintf(t, "cmp $%.2x,s [%.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0xc4: sprintf(t, "cpy $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xc5: sprintf(t, "cmp $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xc6: sprintf(t, "dec $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xc7: sprintf(t, "cmp [$%.2x] [%.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0xc8: sprintf(t, "iny "); break; + case 0xc9: if(a8)sprintf(t, "cmp #$%.2x ", op8); + else sprintf(t, "cmp #$%.4x ", op16); break; + case 0xca: sprintf(t, "dex "); break; + case 0xcb: sprintf(t, "wai "); break; + case 0xcc: sprintf(t, "cpy $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xcd: sprintf(t, "cmp $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xce: sprintf(t, "dec $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xcf: sprintf(t, "cmp $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0xd0: sprintf(t, "bne $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0xd1: sprintf(t, "cmp ($%.2x),y [%.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0xd2: sprintf(t, "cmp ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0xd3: sprintf(t, "cmp ($%.2x,s),y [%.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0xd4: sprintf(t, "pei ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0xd5: sprintf(t, "cmp $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xd6: sprintf(t, "dec $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xd7: sprintf(t, "cmp [$%.2x],y [%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0xd8: sprintf(t, "cld "); break; + case 0xd9: sprintf(t, "cmp $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0xda: sprintf(t, "phx "); break; + case 0xdb: sprintf(t, "stp "); break; + case 0xdc: sprintf(t, "jmp [$%.4x] [%.6x]", op16, decode(OPTYPE_ILADDR, op16)); break; + case 0xdd: sprintf(t, "cmp $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xde: sprintf(t, "dec $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xdf: sprintf(t, "cmp $%.6x,x [%.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + case 0xe0: if(x8)sprintf(t, "cpx #$%.2x ", op8); + else sprintf(t, "cpx #$%.4x ", op16); break; + case 0xe1: sprintf(t, "sbc ($%.2x,x) [%.6x]", op8, decode(OPTYPE_IDPX, op8)); break; + case 0xe2: sprintf(t, "sep #$%.2x ", op8); break; + case 0xe3: sprintf(t, "sbc $%.2x,s [%.6x]", op8, decode(OPTYPE_SR, op8)); break; + case 0xe4: sprintf(t, "cpx $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xe5: sprintf(t, "sbc $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xe6: sprintf(t, "inc $%.2x [%.6x]", op8, decode(OPTYPE_DP, op8)); break; + case 0xe7: sprintf(t, "sbc [$%.2x] [%.6x]", op8, decode(OPTYPE_ILDP, op8)); break; + case 0xe8: sprintf(t, "inx "); break; + case 0xe9: if(a8)sprintf(t, "sbc #$%.2x ", op8); + else sprintf(t, "sbc #$%.4x ", op16); break; + case 0xea: sprintf(t, "nop "); break; + case 0xeb: sprintf(t, "xba "); break; + case 0xec: sprintf(t, "cpx $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xed: sprintf(t, "sbc $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xee: sprintf(t, "inc $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xef: sprintf(t, "sbc $%.6x [%.6x]", op24, decode(OPTYPE_LONG, op24)); break; + case 0xf0: sprintf(t, "beq $%.4x [%.6x]", uint16(decode(OPTYPE_RELB, op8)), decode(OPTYPE_RELB, op8)); break; + case 0xf1: sprintf(t, "sbc ($%.2x),y [%.6x]", op8, decode(OPTYPE_IDPY, op8)); break; + case 0xf2: sprintf(t, "sbc ($%.2x) [%.6x]", op8, decode(OPTYPE_IDP, op8)); break; + case 0xf3: sprintf(t, "sbc ($%.2x,s),y [%.6x]", op8, decode(OPTYPE_ISRY, op8)); break; + case 0xf4: sprintf(t, "pea $%.4x [%.6x]", op16, decode(OPTYPE_ADDR, op16)); break; + case 0xf5: sprintf(t, "sbc $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xf6: sprintf(t, "inc $%.2x,x [%.6x]", op8, decode(OPTYPE_DPX, op8)); break; + case 0xf7: sprintf(t, "sbc [$%.2x],y [%.6x]", op8, decode(OPTYPE_ILDPY, op8)); break; + case 0xf8: sprintf(t, "sed "); break; + case 0xf9: sprintf(t, "sbc $%.4x,y [%.6x]", op16, decode(OPTYPE_ADDRY, op16)); break; + case 0xfa: sprintf(t, "plx "); break; + case 0xfb: sprintf(t, "xce "); break; + case 0xfc: sprintf(t, "jsr ($%.4x,x) [%.6x]", op16, decode(OPTYPE_IADDRX, op16)); break; + case 0xfd: sprintf(t, "sbc $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xfe: sprintf(t, "inc $%.4x,x [%.6x]", op16, decode(OPTYPE_ADDRX, op16)); break; + case 0xff: sprintf(t, "sbc $%.6x,x [%.6x]", op24, decode(OPTYPE_LONGX, op24)); break; + } + + #undef op8 + #undef op16 + #undef op24 + #undef a8 + #undef x8 + + strcat(s, t); + strcat(s, " "); + + sprintf(t, "A:%.4x X:%.4x Y:%.4x S:%.4x D:%.4x DB:%.2x ", + regs.a.w, regs.x.w, regs.y.w, regs.s.w, regs.d.w, regs.db); + strcat(s, t); + + if(regs.e) { + sprintf(t, "%c%c%c%c%c%c%c%c", + regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v', + regs.p.m ? '1' : '0', regs.p.x ? 'B' : 'b', + regs.p.d ? 'D' : 'd', regs.p.i ? 'I' : 'i', + regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c'); + } else { + sprintf(t, "%c%c%c%c%c%c%c%c", + regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v', + regs.p.m ? 'M' : 'm', regs.p.x ? 'X' : 'x', + regs.p.d ? 'D' : 'd', regs.p.i ? 'I' : 'i', + regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c'); + } + + strcat(s, t); + strcat(s, " "); + + sprintf(t, "V:%3d H:%4d", cpu.vcounter(), cpu.hcounter()); + strcat(s, t); +} + +//opcode_length() retrieves the length of the next opcode +//to be executed. It is used by the debugger to step over, +//disable and proceed cpu opcodes. +// +//5 and 6 are special cases, 5 is used for #consts based on +//the A register size, 6 for the X/Y register size. the +//rest are literal sizes. There's no need to test for +//emulation mode, as regs.p.m/regs.p.x should *always* be +//set in emulation mode. + +uint8 CPUcore::opcode_length() { + uint8 op, len; + static uint8 op_len_tbl[256] = { + //0,1,2,3, 4,5,6,7, 8,9,a,b, c,d,e,f + + 2,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x0n + 2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x1n + 3,2,4,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x2n + 2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x3n + + 1,2,2,2, 3,2,2,2, 1,5,1,1, 3,3,3,4, //0x4n + 2,2,2,2, 3,2,2,2, 1,3,1,1, 4,3,3,4, //0x5n + 1,2,3,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x6n + 2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x7n + + 2,2,3,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0x8n + 2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0x9n + 6,2,6,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xan + 2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0xbn + + 6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xcn + 2,2,2,2, 2,2,2,2, 1,3,1,1, 3,3,3,4, //0xdn + 6,2,2,2, 2,2,2,2, 1,5,1,1, 3,3,3,4, //0xen + 2,2,2,2, 3,2,2,2, 1,3,1,1, 3,3,3,4 //0xfn + }; + + if(false /* in_opcode() == true */) { + return 0; + } + + op = dreadb(regs.pc.d); + len = op_len_tbl[op]; + if(len == 5) return (regs.e || regs.p.m) ? 2 : 3; + if(len == 6) return (regs.e || regs.p.x) ? 2 : 3; + return len; +} + +#endif diff --git a/snes/cpu/core/disassembler/disassembler.hpp b/snes/cpu/core/disassembler/disassembler.hpp new file mode 100755 index 00000000..b0ee6f04 --- /dev/null +++ b/snes/cpu/core/disassembler/disassembler.hpp @@ -0,0 +1,30 @@ +enum { + OPTYPE_DP = 0, //dp + OPTYPE_DPX, //dp,x + OPTYPE_DPY, //dp,y + OPTYPE_IDP, //(dp) + OPTYPE_IDPX, //(dp,x) + OPTYPE_IDPY, //(dp),y + OPTYPE_ILDP, //[dp] + OPTYPE_ILDPY, //[dp],y + OPTYPE_ADDR, //addr + OPTYPE_ADDRX, //addr,x + OPTYPE_ADDRY, //addr,y + OPTYPE_IADDRX, //(addr,x) + OPTYPE_ILADDR, //[addr] + OPTYPE_LONG, //long + OPTYPE_LONGX, //long, x + OPTYPE_SR, //sr,s + OPTYPE_ISRY, //(sr,s),y + OPTYPE_ADDR_PC, //pbr:addr + OPTYPE_IADDR_PC, //pbr:(addr) + OPTYPE_RELB, //relb + OPTYPE_RELW, //relw +}; + +void disassemble_opcode(char *output, uint32 addr); +uint8 dreadb(uint32 addr); +uint16 dreadw(uint32 addr); +uint32 dreadl(uint32 addr); +uint32 decode(uint8 offset_type, uint32 addr); +uint8 opcode_length(); diff --git a/snes/cpu/core/memory.hpp b/snes/cpu/core/memory.hpp new file mode 100755 index 00000000..49926578 --- /dev/null +++ b/snes/cpu/core/memory.hpp @@ -0,0 +1,77 @@ +alwaysinline uint8_t op_readpc() { + return op_read((regs.pc.b << 16) + regs.pc.w++); +} + +alwaysinline uint8_t op_readstack() { + regs.e ? regs.s.l++ : regs.s.w++; + return op_read(regs.s.w); +} + +alwaysinline uint8_t op_readstackn() { + return op_read(++regs.s.w); +} + +alwaysinline uint8_t op_readaddr(uint32_t addr) { + return op_read(addr & 0xffff); +} + +alwaysinline uint8_t op_readlong(uint32_t addr) { + return op_read(addr & 0xffffff); +} + +alwaysinline uint8_t op_readdbr(uint32_t addr) { + return op_read(((regs.db << 16) + addr) & 0xffffff); +} + +alwaysinline uint8_t op_readpbr(uint32_t addr) { + return op_read((regs.pc.b << 16) + (addr & 0xffff)); +} + +alwaysinline uint8_t op_readdp(uint32_t addr) { + if(regs.e && regs.d.l == 0x00) { + return op_read((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff)); + } else { + return op_read((regs.d + (addr & 0xffff)) & 0xffff); + } +} + +alwaysinline uint8_t op_readsp(uint32_t addr) { + return op_read((regs.s + (addr & 0xffff)) & 0xffff); +} + +alwaysinline void op_writestack(uint8_t data) { + op_write(regs.s.w, data); + regs.e ? regs.s.l-- : regs.s.w--; +} + +alwaysinline void op_writestackn(uint8_t data) { + op_write(regs.s.w--, data); +} + +alwaysinline void op_writeaddr(uint32_t addr, uint8_t data) { + op_write(addr & 0xffff, data); +} + +alwaysinline void op_writelong(uint32_t addr, uint8_t data) { + op_write(addr & 0xffffff, data); +} + +alwaysinline void op_writedbr(uint32_t addr, uint8_t data) { + op_write(((regs.db << 16) + addr) & 0xffffff, data); +} + +alwaysinline void op_writepbr(uint32_t addr, uint8_t data) { + op_write((regs.pc.b << 16) + (addr & 0xffff), data); +} + +alwaysinline void op_writedp(uint32_t addr, uint8_t data) { + if(regs.e && regs.d.l == 0x00) { + op_write((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff), data); + } else { + op_write((regs.d + (addr & 0xffff)) & 0xffff, data); + } +} + +alwaysinline void op_writesp(uint32_t addr, uint8_t data) { + op_write((regs.s + (addr & 0xffff)) & 0xffff, data); +} diff --git a/snes/cpu/core/opcode_misc.cpp b/snes/cpu/core/opcode_misc.cpp new file mode 100755 index 00000000..8087fe66 --- /dev/null +++ b/snes/cpu/core/opcode_misc.cpp @@ -0,0 +1,338 @@ +#ifdef CPUCORE_CPP + +void CPUcore::op_nop() { +L op_io_irq(); +} + +void CPUcore::op_wdm() { +L op_readpc(); +} + +void CPUcore::op_xba() { + op_io(); +L op_io(); + regs.a.l ^= regs.a.h; + regs.a.h ^= regs.a.l; + regs.a.l ^= regs.a.h; + regs.p.n = (regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +template void CPUcore::op_move_b() { + dp = op_readpc(); + sp = op_readpc(); + regs.db = dp; + rd.l = op_readlong((sp << 16) | regs.x.w); + op_writelong((dp << 16) | regs.y.w, rd.l); + op_io(); + regs.x.l += adjust; + regs.y.l += adjust; +L op_io(); + if(regs.a.w--) regs.pc.w -= 3; +} + +template void CPUcore::op_move_w() { + dp = op_readpc(); + sp = op_readpc(); + regs.db = dp; + rd.l = op_readlong((sp << 16) | regs.x.w); + op_writelong((dp << 16) | regs.y.w, rd.l); + op_io(); + regs.x.w += adjust; + regs.y.w += adjust; +L op_io(); + if(regs.a.w--) regs.pc.w -= 3; +} + +template void CPUcore::op_interrupt_e() { + op_readpc(); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + op_writestack(regs.p); + rd.l = op_readlong(vectorE + 0); + regs.pc.b = 0; + regs.p.i = 1; + regs.p.d = 0; +L rd.h = op_readlong(vectorE + 1); + regs.pc.w = rd.w; +} + +template void CPUcore::op_interrupt_n() { + op_readpc(); + op_writestack(regs.pc.b); + op_writestack(regs.pc.h); + op_writestack(regs.pc.l); + op_writestack(regs.p); + rd.l = op_readlong(vectorN + 0); + regs.pc.b = 0x00; + regs.p.i = 1; + regs.p.d = 0; +L rd.h = op_readlong(vectorN + 1); + regs.pc.w = rd.w; +} + +void CPUcore::op_stp() { + while(regs.wai = true) { +L op_io(); + } +} + +void CPUcore::op_wai() { + regs.wai = true; + while(regs.wai) { +L op_io(); + } + op_io(); +} + +void CPUcore::op_xce() { +L op_io_irq(); + bool carry = regs.p.c; + regs.p.c = regs.e; + regs.e = carry; + if(regs.e) { + regs.p |= 0x30; + regs.s.h = 0x01; + } + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } + update_table(); +} + +template void CPUcore::op_flag() { +L op_io_irq(); + regs.p = (regs.p & ~mask) | value; +} + +template void CPUcore::op_pflag_e() { + rd.l = op_readpc(); +L op_io(); + regs.p = (mode ? regs.p | rd.l : regs.p & ~rd.l); + regs.p |= 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } + update_table(); +} + +template void CPUcore::op_pflag_n() { + rd.l = op_readpc(); +L op_io(); + regs.p = (mode ? regs.p | rd.l : regs.p & ~rd.l); + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } + update_table(); +} + +template void CPUcore::op_transfer_b() { +L op_io_irq(); + regs.r[to].l = regs.r[from].l; + regs.p.n = (regs.r[to].l & 0x80); + regs.p.z = (regs.r[to].l == 0); +} + +template void CPUcore::op_transfer_w() { +L op_io_irq(); + regs.r[to].w = regs.r[from].w; + regs.p.n = (regs.r[to].w & 0x8000); + regs.p.z = (regs.r[to].w == 0); +} + +void CPUcore::op_tcs_e() { +L op_io_irq(); + regs.s.l = regs.a.l; +} + +void CPUcore::op_tcs_n() { +L op_io_irq(); + regs.s.w = regs.a.w; +} + +void CPUcore::op_tsx_b() { +L op_io_irq(); + regs.x.l = regs.s.l; + regs.p.n = (regs.x.l & 0x80); + regs.p.z = (regs.x.l == 0); +} + +void CPUcore::op_tsx_w() { +L op_io_irq(); + regs.x.w = regs.s.w; + regs.p.n = (regs.x.w & 0x8000); + regs.p.z = (regs.x.w == 0); +} + +void CPUcore::op_txs_e() { +L op_io_irq(); + regs.s.l = regs.x.l; +} + +void CPUcore::op_txs_n() { +L op_io_irq(); + regs.s.w = regs.x.w; +} + +template void CPUcore::op_push_b() { + op_io(); +L op_writestack(regs.r[n].l); +} + +template void CPUcore::op_push_w() { + op_io(); + op_writestack(regs.r[n].h); +L op_writestack(regs.r[n].l); +} + +void CPUcore::op_phd_e() { + op_io(); + op_writestackn(regs.d.h); +L op_writestackn(regs.d.l); + regs.s.h = 0x01; +} + +void CPUcore::op_phd_n() { + op_io(); + op_writestackn(regs.d.h); +L op_writestackn(regs.d.l); +} + +void CPUcore::op_phb() { + op_io(); +L op_writestack(regs.db); +} + +void CPUcore::op_phk() { + op_io(); +L op_writestack(regs.pc.b); +} + +void CPUcore::op_php() { + op_io(); +L op_writestack(regs.p); +} + +template void CPUcore::op_pull_b() { + op_io(); + op_io(); +L regs.r[n].l = op_readstack(); + regs.p.n = (regs.r[n].l & 0x80); + regs.p.z = (regs.r[n].l == 0); +} + +template void CPUcore::op_pull_w() { + op_io(); + op_io(); + regs.r[n].l = op_readstack(); +L regs.r[n].h = op_readstack(); + regs.p.n = (regs.r[n].w & 0x8000); + regs.p.z = (regs.r[n].w == 0); +} + +void CPUcore::op_pld_e() { + op_io(); + op_io(); + regs.d.l = op_readstackn(); +L regs.d.h = op_readstackn(); + regs.p.n = (regs.d.w & 0x8000); + regs.p.z = (regs.d.w == 0); + regs.s.h = 0x01; +} + +void CPUcore::op_pld_n() { + op_io(); + op_io(); + regs.d.l = op_readstackn(); +L regs.d.h = op_readstackn(); + regs.p.n = (regs.d.w & 0x8000); + regs.p.z = (regs.d.w == 0); +} + +void CPUcore::op_plb() { + op_io(); + op_io(); +L regs.db = op_readstack(); + regs.p.n = (regs.db & 0x80); + regs.p.z = (regs.db == 0); +} + +void CPUcore::op_plp_e() { + op_io(); + op_io(); +L regs.p = op_readstack() | 0x30; + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } + update_table(); +} + +void CPUcore::op_plp_n() { + op_io(); + op_io(); +L regs.p = op_readstack(); + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } + update_table(); +} + +void CPUcore::op_pea_e() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_writestackn(aa.h); +L op_writestackn(aa.l); + regs.s.h = 0x01; +} + +void CPUcore::op_pea_n() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_writestackn(aa.h); +L op_writestackn(aa.l); +} + +void CPUcore::op_pei_e() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + op_writestackn(aa.h); +L op_writestackn(aa.l); + regs.s.h = 0x01; +} + +void CPUcore::op_pei_n() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + op_writestackn(aa.h); +L op_writestackn(aa.l); +} + +void CPUcore::op_per_e() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.w = regs.pc.d + (int16)aa.w; + op_writestackn(rd.h); +L op_writestackn(rd.l); + regs.s.h = 0x01; +} + +void CPUcore::op_per_n() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.w = regs.pc.d + (int16)aa.w; + op_writestackn(rd.h); +L op_writestackn(rd.l); +} + +#endif diff --git a/snes/cpu/core/opcode_pc.cpp b/snes/cpu/core/opcode_pc.cpp new file mode 100755 index 00000000..3b4543f3 --- /dev/null +++ b/snes/cpu/core/opcode_pc.cpp @@ -0,0 +1,181 @@ +#ifdef CPUCORE_CPP + +template void CPUcore::op_branch() { + if((bool)(regs.p & bit) != val) { +L rd.l = op_readpc(); + } else { + rd.l = op_readpc(); + aa.w = regs.pc.d + (int8)rd.l; + op_io_cond6(aa.w); +L op_io(); + regs.pc.w = aa.w; + } +} + +void CPUcore::op_bra() { + rd.l = op_readpc(); + aa.w = regs.pc.d + (int8)rd.l; + op_io_cond6(aa.w); +L op_io(); + regs.pc.w = aa.w; +} + +void CPUcore::op_brl() { + rd.l = op_readpc(); + rd.h = op_readpc(); +L op_io(); + regs.pc.w = regs.pc.d + (int16)rd.w; +} + +void CPUcore::op_jmp_addr() { + rd.l = op_readpc(); +L rd.h = op_readpc(); + regs.pc.w = rd.w; +} + +void CPUcore::op_jmp_long() { + rd.l = op_readpc(); + rd.h = op_readpc(); +L rd.b = op_readpc(); + regs.pc.d = rd.d & 0xffffff; +} + +void CPUcore::op_jmp_iaddr() { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readaddr(aa.w + 0); +L rd.h = op_readaddr(aa.w + 1); + regs.pc.w = rd.w; +} + +void CPUcore::op_jmp_iaddrx() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readpbr(aa.w + regs.x.w + 0); +L rd.h = op_readpbr(aa.w + regs.x.w + 1); + regs.pc.w = rd.w; +} + +void CPUcore::op_jmp_iladdr() { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readaddr(aa.w + 0); + rd.h = op_readaddr(aa.w + 1); +L rd.b = op_readaddr(aa.w + 2); + regs.pc.d = rd.d & 0xffffff; +} + +void CPUcore::op_jsr_addr() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + regs.pc.w--; + op_writestack(regs.pc.h); +L op_writestack(regs.pc.l); + regs.pc.w = aa.w; +} + +void CPUcore::op_jsr_long_e() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_writestackn(regs.pc.b); + op_io(); + aa.b = op_readpc(); + regs.pc.w--; + op_writestackn(regs.pc.h); +L op_writestackn(regs.pc.l); + regs.pc.d = aa.d & 0xffffff; + regs.s.h = 0x01; +} + +void CPUcore::op_jsr_long_n() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_writestackn(regs.pc.b); + op_io(); + aa.b = op_readpc(); + regs.pc.w--; + op_writestackn(regs.pc.h); +L op_writestackn(regs.pc.l); + regs.pc.d = aa.d & 0xffffff; +} + +void CPUcore::op_jsr_iaddrx_e() { + aa.l = op_readpc(); + op_writestackn(regs.pc.h); + op_writestackn(regs.pc.l); + aa.h = op_readpc(); + op_io(); + rd.l = op_readpbr(aa.w + regs.x.w + 0); +L rd.h = op_readpbr(aa.w + regs.x.w + 1); + regs.pc.w = rd.w; + regs.s.h = 0x01; +} + +void CPUcore::op_jsr_iaddrx_n() { + aa.l = op_readpc(); + op_writestackn(regs.pc.h); + op_writestackn(regs.pc.l); + aa.h = op_readpc(); + op_io(); + rd.l = op_readpbr(aa.w + regs.x.w + 0); +L rd.h = op_readpbr(aa.w + regs.x.w + 1); + regs.pc.w = rd.w; +} + +void CPUcore::op_rti_e() { + op_io(); + op_io(); + regs.p = op_readstack() | 0x30; + rd.l = op_readstack(); +L rd.h = op_readstack(); + regs.pc.w = rd.w; +} + +void CPUcore::op_rti_n() { + op_io(); + op_io(); + regs.p = op_readstack(); + if(regs.p.x) { + regs.x.h = 0x00; + regs.y.h = 0x00; + } + rd.l = op_readstack(); + rd.h = op_readstack(); +L rd.b = op_readstack(); + regs.pc.d = rd.d & 0xffffff; + update_table(); +} + +void CPUcore::op_rts() { + op_io(); + op_io(); + rd.l = op_readstack(); + rd.h = op_readstack(); +L op_io(); + regs.pc.w = ++rd.w; +} + +void CPUcore::op_rtl_e() { + op_io(); + op_io(); + rd.l = op_readstackn(); + rd.h = op_readstackn(); +L rd.b = op_readstackn(); + regs.pc.b = rd.b; + regs.pc.w = ++rd.w; + regs.s.h = 0x01; +} + +void CPUcore::op_rtl_n() { + op_io(); + op_io(); + rd.l = op_readstackn(); + rd.h = op_readstackn(); +L rd.b = op_readstackn(); + regs.pc.b = rd.b; + regs.pc.w = ++rd.w; +} + +#endif diff --git a/snes/cpu/core/opcode_read.cpp b/snes/cpu/core/opcode_read.cpp new file mode 100755 index 00000000..61a7feb3 --- /dev/null +++ b/snes/cpu/core/opcode_read.cpp @@ -0,0 +1,279 @@ +#ifdef CPUCORE_CPP + +template void CPUcore::op_read_const_b() { +L rd.l = op_readpc(); + call(op); +} + +template void CPUcore::op_read_const_w() { + rd.l = op_readpc(); +L rd.h = op_readpc(); + call(op); +} + +void CPUcore::op_read_bit_const_b() { +L rd.l = op_readpc(); + regs.p.z = ((rd.l & regs.a.l) == 0); +} + +void CPUcore::op_read_bit_const_w() { + rd.l = op_readpc(); +L rd.h = op_readpc(); + regs.p.z = ((rd.w & regs.a.w) == 0); +} + +template void CPUcore::op_read_addr_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); +L rd.l = op_readdbr(aa.w); + call(op); +} + +template void CPUcore::op_read_addr_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w + 0); +L rd.h = op_readdbr(aa.w + 1); + call(op); +} + +template void CPUcore::op_read_addrx_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); +L rd.l = op_readdbr(aa.w + regs.x.w); + call(op); +} + +template void CPUcore::op_read_addrx_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.x.w); + rd.l = op_readdbr(aa.w + regs.x.w + 0); +L rd.h = op_readdbr(aa.w + regs.x.w + 1); + call(op); +} + +template void CPUcore::op_read_addry_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); +L rd.l = op_readdbr(aa.w + regs.y.w); + call(op); +} + +template void CPUcore::op_read_addry_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io_cond4(aa.w, aa.w + regs.y.w); + rd.l = op_readdbr(aa.w + regs.y.w + 0); +L rd.h = op_readdbr(aa.w + regs.y.w + 1); + call(op); +} + +template void CPUcore::op_read_long_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); +L rd.l = op_readlong(aa.d); + call(op); +} + +template void CPUcore::op_read_long_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + rd.l = op_readlong(aa.d + 0); +L rd.h = op_readlong(aa.d + 1); + call(op); +} + +template void CPUcore::op_read_longx_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); +L rd.l = op_readlong(aa.d + regs.x.w); + call(op); +} + +template void CPUcore::op_read_longx_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + rd.l = op_readlong(aa.d + regs.x.w + 0); +L rd.h = op_readlong(aa.d + regs.x.w + 1); + call(op); +} + +template void CPUcore::op_read_dp_b() { + dp = op_readpc(); + op_io_cond2(); +L rd.l = op_readdp(dp); + call(op); +} + +template void CPUcore::op_read_dp_w() { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp + 0); +L rd.h = op_readdp(dp + 1); + call(op); +} + +template void CPUcore::op_read_dpr_b() { + dp = op_readpc(); + op_io_cond2(); + op_io(); +L rd.l = op_readdp(dp + regs.r[n].w); + call(op); +} + +template void CPUcore::op_read_dpr_w() { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.r[n].w + 0); +L rd.h = op_readdp(dp + regs.r[n].w + 1); + call(op); +} + +template void CPUcore::op_read_idp_b() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); +L rd.l = op_readdbr(aa.w); + call(op); +} + +template void CPUcore::op_read_idp_w() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + rd.l = op_readdbr(aa.w + 0); +L rd.h = op_readdbr(aa.w + 1); + call(op); +} + +template void CPUcore::op_read_idpx_b() { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w + 0); + aa.h = op_readdp(dp + regs.x.w + 1); +L rd.l = op_readdbr(aa.w); + call(op); +} + +template void CPUcore::op_read_idpx_w() { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w + 0); + aa.h = op_readdp(dp + regs.x.w + 1); + rd.l = op_readdbr(aa.w + 0); +L rd.h = op_readdbr(aa.w + 1); + call(op); +} + +template void CPUcore::op_read_idpy_b() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); +L rd.l = op_readdbr(aa.w + regs.y.w); + call(op); +} + +template void CPUcore::op_read_idpy_w() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + op_io_cond4(aa.w, aa.w + regs.y.w); + rd.l = op_readdbr(aa.w + regs.y.w + 0); +L rd.h = op_readdbr(aa.w + regs.y.w + 1); + call(op); +} + +template void CPUcore::op_read_ildp_b() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); +L rd.l = op_readlong(aa.d); + call(op); +} + +template void CPUcore::op_read_ildp_w() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + rd.l = op_readlong(aa.d + 0); +L rd.h = op_readlong(aa.d + 1); + call(op); +} + +template void CPUcore::op_read_ildpy_b() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); +L rd.l = op_readlong(aa.d + regs.y.w); + call(op); +} + +template void CPUcore::op_read_ildpy_w() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + rd.l = op_readlong(aa.d + regs.y.w + 0); +L rd.h = op_readlong(aa.d + regs.y.w + 1); + call(op); +} + +template void CPUcore::op_read_sr_b() { + sp = op_readpc(); + op_io(); +L rd.l = op_readsp(sp); + call(op); +} + +template void CPUcore::op_read_sr_w() { + sp = op_readpc(); + op_io(); + rd.l = op_readsp(sp + 0); +L rd.h = op_readsp(sp + 1); + call(op); +} + +template void CPUcore::op_read_isry_b() { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp + 0); + aa.h = op_readsp(sp + 1); + op_io(); +L rd.l = op_readdbr(aa.w + regs.y.w); + call(op); +} + +template void CPUcore::op_read_isry_w() { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp + 0); + aa.h = op_readsp(sp + 1); + op_io(); + rd.l = op_readdbr(aa.w + regs.y.w + 0); +L rd.h = op_readdbr(aa.w + regs.y.w + 1); + call(op); +} + +#endif diff --git a/snes/cpu/core/opcode_rmw.cpp b/snes/cpu/core/opcode_rmw.cpp new file mode 100755 index 00000000..fed939e1 --- /dev/null +++ b/snes/cpu/core/opcode_rmw.cpp @@ -0,0 +1,169 @@ +#ifdef CPUCORE_CPP + +template void CPUcore::op_adjust_imm_b() { +L op_io_irq(); + regs.r[n].l += adjust; + regs.p.n = (regs.r[n].l & 0x80); + regs.p.z = (regs.r[n].l == 0); +} + +template void CPUcore::op_adjust_imm_w() { +L op_io_irq(); + regs.r[n].w += adjust; + regs.p.n = (regs.r[n].w & 0x8000); + regs.p.z = (regs.r[n].w == 0); +} + +void CPUcore::op_asl_imm_b() { +L op_io_irq(); + regs.p.c = (regs.a.l & 0x80); + regs.a.l <<= 1; + regs.p.n = (regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +void CPUcore::op_asl_imm_w() { +L op_io_irq(); + regs.p.c = (regs.a.w & 0x8000); + regs.a.w <<= 1; + regs.p.n = (regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +void CPUcore::op_lsr_imm_b() { +L op_io_irq(); + regs.p.c = (regs.a.l & 0x01); + regs.a.l >>= 1; + regs.p.n = (regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +void CPUcore::op_lsr_imm_w() { +L op_io_irq(); + regs.p.c = (regs.a.w & 0x0001); + regs.a.w >>= 1; + regs.p.n = (regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +void CPUcore::op_rol_imm_b() { +L op_io_irq(); + bool carry = regs.p.c; + regs.p.c = (regs.a.l & 0x80); + regs.a.l = (regs.a.l << 1) | carry; + regs.p.n = (regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +void CPUcore::op_rol_imm_w() { +L op_io_irq(); + bool carry = regs.p.c; + regs.p.c = (regs.a.w & 0x8000); + regs.a.w = (regs.a.w << 1) | carry; + regs.p.n = (regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +void CPUcore::op_ror_imm_b() { +L op_io_irq(); + bool carry = regs.p.c; + regs.p.c = (regs.a.l & 0x01); + regs.a.l = (carry << 7) | (regs.a.l >> 1); + regs.p.n = (regs.a.l & 0x80); + regs.p.z = (regs.a.l == 0); +} + +void CPUcore::op_ror_imm_w() { +L op_io_irq(); + bool carry = regs.p.c; + regs.p.c = (regs.a.w & 0x0001); + regs.a.w = (carry << 15) | (regs.a.w >> 1); + regs.p.n = (regs.a.w & 0x8000); + regs.p.z = (regs.a.w == 0); +} + +template void CPUcore::op_adjust_addr_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w); + op_io(); + call(op); +L op_writedbr(aa.w, rd.l); +} + +template void CPUcore::op_adjust_addr_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + rd.l = op_readdbr(aa.w + 0); + rd.h = op_readdbr(aa.w + 1); + op_io(); + call(op); + op_writedbr(aa.w + 1, rd.h); +L op_writedbr(aa.w + 0, rd.l); +} + +template void CPUcore::op_adjust_addrx_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readdbr(aa.w + regs.x.w); + op_io(); + call(op); +L op_writedbr(aa.w + regs.x.w, rd.l); +} + +template void CPUcore::op_adjust_addrx_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + rd.l = op_readdbr(aa.w + regs.x.w + 0); + rd.h = op_readdbr(aa.w + regs.x.w + 1); + op_io(); + call(op); + op_writedbr(aa.w + regs.x.w + 1, rd.h); +L op_writedbr(aa.w + regs.x.w + 0, rd.l); +} + +template void CPUcore::op_adjust_dp_b() { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp); + op_io(); + call(op); +L op_writedp(dp, rd.l); +} + +template void CPUcore::op_adjust_dp_w() { + dp = op_readpc(); + op_io_cond2(); + rd.l = op_readdp(dp + 0); + rd.h = op_readdp(dp + 1); + op_io(); + call(op); + op_writedp(dp + 1, rd.h); +L op_writedp(dp + 0, rd.l); +} + +template void CPUcore::op_adjust_dpx_b() { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.x.w); + op_io(); + call(op); +L op_writedp(dp + regs.x.w, rd.l); +} + +template void CPUcore::op_adjust_dpx_w() { + dp = op_readpc(); + op_io_cond2(); + op_io(); + rd.l = op_readdp(dp + regs.x.w + 0); + rd.h = op_readdp(dp + regs.x.w + 1); + op_io(); + call(op); + op_writedp(dp + regs.x.w + 1, rd.h); +L op_writedp(dp + regs.x.w + 0, rd.l); +} + +#endif diff --git a/snes/cpu/core/opcode_write.cpp b/snes/cpu/core/opcode_write.cpp new file mode 100755 index 00000000..de85e672 --- /dev/null +++ b/snes/cpu/core/opcode_write.cpp @@ -0,0 +1,199 @@ +#ifdef CPUCORE_CPP + +template void CPUcore::op_write_addr_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); +L op_writedbr(aa.w, regs.r[n]); +} + +template void CPUcore::op_write_addr_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_writedbr(aa.w + 0, regs.r[n] >> 0); +L op_writedbr(aa.w + 1, regs.r[n] >> 8); +} + +template void CPUcore::op_write_addrr_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); +L op_writedbr(aa.w + regs.r[i], regs.r[n]); +} + +template void CPUcore::op_write_addrr_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + op_io(); + op_writedbr(aa.w + regs.r[i] + 0, regs.r[n] >> 0); +L op_writedbr(aa.w + regs.r[i] + 1, regs.r[n] >> 8); +} + +template void CPUcore::op_write_longr_b() { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); +L op_writelong(aa.d + regs.r[i], regs.a.l); +} + +template void CPUcore::op_write_longr_w() { + aa.l = op_readpc(); + aa.h = op_readpc(); + aa.b = op_readpc(); + op_writelong(aa.d + regs.r[i] + 0, regs.a.l); +L op_writelong(aa.d + regs.r[i] + 1, regs.a.h); +} + +template void CPUcore::op_write_dp_b() { + dp = op_readpc(); + op_io_cond2(); +L op_writedp(dp, regs.r[n]); +} + +template void CPUcore::op_write_dp_w() { + dp = op_readpc(); + op_io_cond2(); + op_writedp(dp + 0, regs.r[n] >> 0); +L op_writedp(dp + 1, regs.r[n] >> 8); +} + +template void CPUcore::op_write_dpr_b() { + dp = op_readpc(); + op_io_cond2(); + op_io(); +L op_writedp(dp + regs.r[i], regs.r[n]); +} + +template void CPUcore::op_write_dpr_w() { + dp = op_readpc(); + op_io_cond2(); + op_io(); + op_writedp(dp + regs.r[i] + 0, regs.r[n] >> 0); +L op_writedp(dp + regs.r[i] + 1, regs.r[n] >> 8); +} + +void CPUcore::op_sta_idp_b() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); +L op_writedbr(aa.w, regs.a.l); +} + +void CPUcore::op_sta_idp_w() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + op_writedbr(aa.w + 0, regs.a.l); +L op_writedbr(aa.w + 1, regs.a.h); +} + +void CPUcore::op_sta_ildp_b() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); +L op_writelong(aa.d, regs.a.l); +} + +void CPUcore::op_sta_ildp_w() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + op_writelong(aa.d + 0, regs.a.l); +L op_writelong(aa.d + 1, regs.a.h); +} + +void CPUcore::op_sta_idpx_b() { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w + 0); + aa.h = op_readdp(dp + regs.x.w + 1); +L op_writedbr(aa.w, regs.a.l); +} + +void CPUcore::op_sta_idpx_w() { + dp = op_readpc(); + op_io_cond2(); + op_io(); + aa.l = op_readdp(dp + regs.x.w + 0); + aa.h = op_readdp(dp + regs.x.w + 1); + op_writedbr(aa.w + 0, regs.a.l); +L op_writedbr(aa.w + 1, regs.a.h); +} + +void CPUcore::op_sta_idpy_b() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + op_io(); +L op_writedbr(aa.w + regs.y.w, regs.a.l); +} + +void CPUcore::op_sta_idpy_w() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + op_io(); + op_writedbr(aa.w + regs.y.w + 0, regs.a.l); +L op_writedbr(aa.w + regs.y.w + 1, regs.a.h); +} + +void CPUcore::op_sta_ildpy_b() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); +L op_writelong(aa.d + regs.y.w, regs.a.l); +} + +void CPUcore::op_sta_ildpy_w() { + dp = op_readpc(); + op_io_cond2(); + aa.l = op_readdp(dp + 0); + aa.h = op_readdp(dp + 1); + aa.b = op_readdp(dp + 2); + op_writelong(aa.d + regs.y.w + 0, regs.a.l); +L op_writelong(aa.d + regs.y.w + 1, regs.a.h); +} + +void CPUcore::op_sta_sr_b() { + sp = op_readpc(); + op_io(); +L op_writesp(sp, regs.a.l); +} + +void CPUcore::op_sta_sr_w() { + sp = op_readpc(); + op_io(); + op_writesp(sp + 0, regs.a.l); +L op_writesp(sp + 1, regs.a.h); +} + +void CPUcore::op_sta_isry_b() { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp + 0); + aa.h = op_readsp(sp + 1); + op_io(); +L op_writedbr(aa.w + regs.y.w, regs.a.l); +} + +void CPUcore::op_sta_isry_w() { + sp = op_readpc(); + op_io(); + aa.l = op_readsp(sp + 0); + aa.h = op_readsp(sp + 1); + op_io(); + op_writedbr(aa.w + regs.y.w + 0, regs.a.l); +L op_writedbr(aa.w + regs.y.w + 1, regs.a.h); +} + +#endif diff --git a/snes/cpu/core/registers.hpp b/snes/cpu/core/registers.hpp new file mode 100755 index 00000000..adcf797f --- /dev/null +++ b/snes/cpu/core/registers.hpp @@ -0,0 +1,83 @@ +struct flag_t { + bool n, v, m, x, d, i, z, c; + + inline operator unsigned() const { + return (n << 7) + (v << 6) + (m << 5) + (x << 4) + + (d << 3) + (i << 2) + (z << 1) + (c << 0); + } + + inline unsigned operator=(uint8 data) { + n = data & 0x80; v = data & 0x40; m = data & 0x20; x = data & 0x10; + d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01; + return data; + } + + inline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); } + inline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); } + inline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); } + + flag_t() : n(0), v(0), m(0), x(0), d(0), i(0), z(0), c(0) {} +}; + +struct reg16_t { + union { + uint16 w; + struct { uint8 order_lsb2(l, h); }; + }; + + inline operator unsigned() const { return w; } + inline unsigned operator = (unsigned i) { return w = i; } + inline unsigned operator |= (unsigned i) { return w |= i; } + inline unsigned operator ^= (unsigned i) { return w ^= i; } + inline unsigned operator &= (unsigned i) { return w &= i; } + inline unsigned operator <<= (unsigned i) { return w <<= i; } + inline unsigned operator >>= (unsigned i) { return w >>= i; } + inline unsigned operator += (unsigned i) { return w += i; } + inline unsigned operator -= (unsigned i) { return w -= i; } + inline unsigned operator *= (unsigned i) { return w *= i; } + inline unsigned operator /= (unsigned i) { return w /= i; } + inline unsigned operator %= (unsigned i) { return w %= i; } + + reg16_t() : w(0) {} +}; + +struct reg24_t { + union { + uint32 d; + struct { uint16 order_lsb2(w, wh); }; + struct { uint8 order_lsb4(l, h, b, bh); }; + }; + + inline operator unsigned() const { return d; } + inline unsigned operator = (unsigned i) { return d = uclip<24>(i); } + inline unsigned operator |= (unsigned i) { return d = uclip<24>(d | i); } + inline unsigned operator ^= (unsigned i) { return d = uclip<24>(d ^ i); } + inline unsigned operator &= (unsigned i) { return d = uclip<24>(d & i); } + inline unsigned operator <<= (unsigned i) { return d = uclip<24>(d << i); } + inline unsigned operator >>= (unsigned i) { return d = uclip<24>(d >> i); } + inline unsigned operator += (unsigned i) { return d = uclip<24>(d + i); } + inline unsigned operator -= (unsigned i) { return d = uclip<24>(d - i); } + inline unsigned operator *= (unsigned i) { return d = uclip<24>(d * i); } + inline unsigned operator /= (unsigned i) { return d = uclip<24>(d / i); } + inline unsigned operator %= (unsigned i) { return d = uclip<24>(d % i); } + + reg24_t() : d(0) {} +}; + +struct regs_t { + reg24_t pc; + reg16_t r[6], &a, &x, &y, &z, &s, &d; + flag_t p; + uint8 db; + bool e; + + bool irq; //IRQ pin (0 = low, 1 = trigger) + bool wai; //raised during wai, cleared after interrupt triggered + uint8 mdr; //memory data register + uint16 vector; //interrupt vector address + + regs_t(): + a(r[0]), x(r[1]), y(r[2]), z(r[3]), s(r[4]), d(r[5]), db(0), e(false), irq(false), wai(false), mdr(0), vector(0) { + z = 0; + } +}; diff --git a/snes/cpu/core/serialization.cpp b/snes/cpu/core/serialization.cpp new file mode 100755 index 00000000..81753e96 --- /dev/null +++ b/snes/cpu/core/serialization.cpp @@ -0,0 +1,37 @@ +#ifdef CPUCORE_CPP + +void CPUcore::core_serialize(serializer &s) { + s.integer(regs.pc.d); + + s.integer(regs.a.w); + s.integer(regs.x.w); + s.integer(regs.y.w); + s.integer(regs.z.w); + s.integer(regs.s.w); + s.integer(regs.d.w); + + s.integer(regs.p.n); + s.integer(regs.p.v); + s.integer(regs.p.m); + s.integer(regs.p.x); + s.integer(regs.p.d); + s.integer(regs.p.i); + s.integer(regs.p.z); + s.integer(regs.p.c); + + s.integer(regs.db); + s.integer(regs.e); + s.integer(regs.irq); + s.integer(regs.wai); + s.integer(regs.mdr); + s.integer(regs.vector); + + s.integer(aa.d); + s.integer(rd.d); + s.integer(sp); + s.integer(dp); + + update_table(); +} + +#endif diff --git a/snes/cpu/core/table.cpp b/snes/cpu/core/table.cpp new file mode 100755 index 00000000..6575a4db --- /dev/null +++ b/snes/cpu/core/table.cpp @@ -0,0 +1,312 @@ +#ifdef CPUCORE_CPP + +void CPUcore::initialize_opcode_table() { + #define opA( id, name ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_Mx + id] = op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name; + #define opAII(id, name, x, y ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_Mx + id] = op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name; + #define opE( id, name ) op_table[table_EM + id] = &CPUcore::op_##name##_e; op_table[table_MX + id] = op_table[table_Mx + id] = op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name##_n; + #define opEI( id, name, x ) op_table[table_EM + id] = &CPUcore::op_##name##_e; op_table[table_MX + id] = op_table[table_Mx + id] = op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name##_n; + #define opEII(id, name, x, y ) op_table[table_EM + id] = &CPUcore::op_##name##_e; op_table[table_MX + id] = op_table[table_Mx + id] = op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name##_n; + #define opM( id, name ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_Mx + id] = &CPUcore::op_##name##_b; op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w; + #define opMI( id, name, x ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_Mx + id] = &CPUcore::op_##name##_b; op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w; + #define opMII(id, name, x, y ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_Mx + id] = &CPUcore::op_##name##_b; op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w; + #define opMF( id, name, fn ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_Mx + id] = &CPUcore::op_##name##_b<&CPUcore::op_##fn##_b>; op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w<&CPUcore::op_##fn##_w>; + #define opMFI(id, name, fn, x) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_Mx + id] = &CPUcore::op_##name##_b<&CPUcore::op_##fn##_b, x>; op_table[table_mX + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w<&CPUcore::op_##fn##_w, x>; + #define opX( id, name ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_mX + id] = &CPUcore::op_##name##_b; op_table[table_Mx + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w; + #define opXI( id, name, x ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_mX + id] = &CPUcore::op_##name##_b; op_table[table_Mx + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w; + #define opXII(id, name, x, y ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_mX + id] = &CPUcore::op_##name##_b; op_table[table_Mx + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w; + #define opXF( id, name, fn ) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_mX + id] = &CPUcore::op_##name##_b<&CPUcore::op_##fn##_b>; op_table[table_Mx + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w<&CPUcore::op_##fn##_w>; + #define opXFI(id, name, fn, x) op_table[table_EM + id] = op_table[table_MX + id] = op_table[table_mX + id] = &CPUcore::op_##name##_b<&CPUcore::op_##fn##_b, x>; op_table[table_Mx + id] = op_table[table_mx + id] = &CPUcore::op_##name##_w<&CPUcore::op_##fn##_w, x>; + + opEII(0x00, interrupt, 0xfffe, 0xffe6) + opMF (0x01, read_idpx, ora) + opEII(0x02, interrupt, 0xfff4, 0xffe4) + opMF (0x03, read_sr, ora) + opMF (0x04, adjust_dp, tsb) + opMF (0x05, read_dp, ora) + opMF (0x06, adjust_dp, asl) + opMF (0x07, read_ildp, ora) + opA (0x08, php) + opMF (0x09, read_const, ora) + opM (0x0a, asl_imm) + opE (0x0b, phd) + opMF (0x0c, adjust_addr, tsb) + opMF (0x0d, read_addr, ora) + opMF (0x0e, adjust_addr, asl) + opMF (0x0f, read_long, ora) + opAII(0x10, branch, 0x80, false) + opMF (0x11, read_idpy, ora) + opMF (0x12, read_idp, ora) + opMF (0x13, read_isry, ora) + opMF (0x14, adjust_dp, trb) + opMFI(0x15, read_dpr, ora, X) + opMF (0x16, adjust_dpx, asl) + opMF (0x17, read_ildpy, ora) + opAII(0x18, flag, 0x01, 0x00) + opMF (0x19, read_addry, ora) + opMII(0x1a, adjust_imm, A, +1) + opE (0x1b, tcs) + opMF (0x1c, adjust_addr, trb) + opMF (0x1d, read_addrx, ora) + opMF (0x1e, adjust_addrx, asl) + opMF (0x1f, read_longx, ora) + opA (0x20, jsr_addr) + opMF (0x21, read_idpx, and) + opE (0x22, jsr_long) + opMF (0x23, read_sr, and) + opMF (0x24, read_dp, bit) + opMF (0x25, read_dp, and) + opMF (0x26, adjust_dp, rol) + opMF (0x27, read_ildp, and) + opE (0x28, plp) + opMF (0x29, read_const, and) + opM (0x2a, rol_imm) + opE (0x2b, pld) + opMF (0x2c, read_addr, bit) + opMF (0x2d, read_addr, and) + opMF (0x2e, adjust_addr, rol) + opMF (0x2f, read_long, and) + opAII(0x30, branch, 0x80, true) + opMF (0x31, read_idpy, and) + opMF (0x32, read_idp, and) + opMF (0x33, read_isry, and) + opMFI(0x34, read_dpr, bit, X) + opMFI(0x35, read_dpr, and, X) + opMF (0x36, adjust_dpx, rol) + opMF (0x37, read_ildpy, and) + opAII(0x38, flag, 0x01, 0x01) + opMF (0x39, read_addry, and) + opMII(0x3a, adjust_imm, A, -1) + opAII(0x3b, transfer_w, S, A) + opMF (0x3c, read_addrx, bit) + opMF (0x3d, read_addrx, and) + opMF (0x3e, adjust_addrx, rol) + opMF (0x3f, read_longx, and) + opE (0x40, rti) + opMF (0x41, read_idpx, eor) + opA (0x42, wdm) + opMF (0x43, read_sr, eor) + opXI (0x44, move, -1) + opMF (0x45, read_dp, eor) + opMF (0x46, adjust_dp, lsr) + opMF (0x47, read_ildp, eor) + opMI (0x48, push, A) + opMF (0x49, read_const, eor) + opM (0x4a, lsr_imm) + opA (0x4b, phk) + opA (0x4c, jmp_addr) + opMF (0x4d, read_addr, eor) + opMF (0x4e, adjust_addr, lsr) + opMF (0x4f, read_long, eor) + opAII(0x50, branch, 0x40, false) + opMF (0x51, read_idpy, eor) + opMF (0x52, read_idp, eor) + opMF (0x53, read_isry, eor) + opXI (0x54, move, +1) + opMFI(0x55, read_dpr, eor, X) + opMF (0x56, adjust_dpx, lsr) + opMF (0x57, read_ildpy, eor) + opAII(0x58, flag, 0x04, 0x00) + opMF (0x59, read_addry, eor) + opXI (0x5a, push, Y) + opAII(0x5b, transfer_w, A, D) + opA (0x5c, jmp_long) + opMF (0x5d, read_addrx, eor) + opMF (0x5e, adjust_addrx, lsr) + opMF (0x5f, read_longx, eor) + opA (0x60, rts) + opMF (0x61, read_idpx, adc) + opE (0x62, per) + opMF (0x63, read_sr, adc) + opMI (0x64, write_dp, Z) + opMF (0x65, read_dp, adc) + opMF (0x66, adjust_dp, ror) + opMF (0x67, read_ildp, adc) + opMI (0x68, pull, A) + opMF (0x69, read_const, adc) + opM (0x6a, ror_imm) + opE (0x6b, rtl) + opA (0x6c, jmp_iaddr) + opMF (0x6d, read_addr, adc) + opMF (0x6e, adjust_addr, ror) + opMF (0x6f, read_long, adc) + opAII(0x70, branch, 0x40, true) + opMF (0x71, read_idpy, adc) + opMF (0x72, read_idp, adc) + opMF (0x73, read_isry, adc) + opMII(0x74, write_dpr, Z, X) + opMFI(0x75, read_dpr, adc, X) + opMF (0x76, adjust_dpx, ror) + opMF (0x77, read_ildpy, adc) + opAII(0x78, flag, 0x04, 0x04) + opMF (0x79, read_addry, adc) + opXI (0x7a, pull, Y) + opAII(0x7b, transfer_w, D, A) + opA (0x7c, jmp_iaddrx) + opMF (0x7d, read_addrx, adc) + opMF (0x7e, adjust_addrx, ror) + opMF (0x7f, read_longx, adc) + opA (0x80, bra) + opM (0x81, sta_idpx) + opA (0x82, brl) + opM (0x83, sta_sr) + opXI (0x84, write_dp, Y) + opMI (0x85, write_dp, A) + opXI (0x86, write_dp, X) + opM (0x87, sta_ildp) + opXII(0x88, adjust_imm, Y, -1) + opM (0x89, read_bit_const) + opMII(0x8a, transfer, X, A) + opA (0x8b, phb) + opXI (0x8c, write_addr, Y) + opMI (0x8d, write_addr, A) + opXI (0x8e, write_addr, X) + opMI (0x8f, write_longr, Z) + opAII(0x90, branch, 0x01, false) + opM (0x91, sta_idpy) + opM (0x92, sta_idp) + opM (0x93, sta_isry) + opXII(0x94, write_dpr, Y, X) + opMII(0x95, write_dpr, A, X) + opXII(0x96, write_dpr, X, Y) + opM (0x97, sta_ildpy) + opMII(0x98, transfer, Y, A) + opMII(0x99, write_addrr, A, Y) + opE (0x9a, txs) + opXII(0x9b, transfer, X, Y) + opMI (0x9c, write_addr, Z) + opMII(0x9d, write_addrr, A, X) + opMII(0x9e, write_addrr, Z, X) + opMI (0x9f, write_longr, X) + opXF (0xa0, read_const, ldy) + opMF (0xa1, read_idpx, lda) + opXF (0xa2, read_const, ldx) + opMF (0xa3, read_sr, lda) + opXF (0xa4, read_dp, ldy) + opMF (0xa5, read_dp, lda) + opXF (0xa6, read_dp, ldx) + opMF (0xa7, read_ildp, lda) + opXII(0xa8, transfer, A, Y) + opMF (0xa9, read_const, lda) + opXII(0xaa, transfer, A, X) + opA (0xab, plb) + opXF (0xac, read_addr, ldy) + opMF (0xad, read_addr, lda) + opXF (0xae, read_addr, ldx) + opMF (0xaf, read_long, lda) + opAII(0xb0, branch, 0x01, true) + opMF (0xb1, read_idpy, lda) + opMF (0xb2, read_idp, lda) + opMF (0xb3, read_isry, lda) + opXFI(0xb4, read_dpr, ldy, X) + opMFI(0xb5, read_dpr, lda, X) + opXFI(0xb6, read_dpr, ldx, Y) + opMF (0xb7, read_ildpy, lda) + opAII(0xb8, flag, 0x40, 0x00) + opMF (0xb9, read_addry, lda) + opX (0xba, tsx) + opXII(0xbb, transfer, Y, X) + opXF (0xbc, read_addrx, ldy) + opMF (0xbd, read_addrx, lda) + opXF (0xbe, read_addry, ldx) + opMF (0xbf, read_longx, lda) + opXF (0xc0, read_const, cpy) + opMF (0xc1, read_idpx, cmp) + opEI (0xc2, pflag, 0) + opMF (0xc3, read_sr, cmp) + opXF (0xc4, read_dp, cpy) + opMF (0xc5, read_dp, cmp) + opMF (0xc6, adjust_dp, dec) + opMF (0xc7, read_ildp, cmp) + opXII(0xc8, adjust_imm, Y, +1) + opMF (0xc9, read_const, cmp) + opXII(0xca, adjust_imm, X, -1) + opA (0xcb, wai) + opXF (0xcc, read_addr, cpy) + opMF (0xcd, read_addr, cmp) + opMF (0xce, adjust_addr, dec) + opMF (0xcf, read_long, cmp) + opAII(0xd0, branch, 0x02, false) + opMF (0xd1, read_idpy, cmp) + opMF (0xd2, read_idp, cmp) + opMF (0xd3, read_isry, cmp) + opE (0xd4, pei) + opMFI(0xd5, read_dpr, cmp, X) + opMF (0xd6, adjust_dpx, dec) + opMF (0xd7, read_ildpy, cmp) + opAII(0xd8, flag, 0x08, 0x00) + opMF (0xd9, read_addry, cmp) + opXI (0xda, push, X) + opA (0xdb, stp) + opA (0xdc, jmp_iladdr) + opMF (0xdd, read_addrx, cmp) + opMF (0xde, adjust_addrx, dec) + opMF (0xdf, read_longx, cmp) + opXF (0xe0, read_const, cpx) + opMF (0xe1, read_idpx, sbc) + opEI (0xe2, pflag, 1) + opMF (0xe3, read_sr, sbc) + opXF (0xe4, read_dp, cpx) + opMF (0xe5, read_dp, sbc) + opMF (0xe6, adjust_dp, inc) + opMF (0xe7, read_ildp, sbc) + opXII(0xe8, adjust_imm, X, +1) + opMF (0xe9, read_const, sbc) + opA (0xea, nop) + opA (0xeb, xba) + opXF (0xec, read_addr, cpx) + opMF (0xed, read_addr, sbc) + opMF (0xee, adjust_addr, inc) + opMF (0xef, read_long, sbc) + opAII(0xf0, branch, 0x02, true) + opMF (0xf1, read_idpy, sbc) + opMF (0xf2, read_idp, sbc) + opMF (0xf3, read_isry, sbc) + opE (0xf4, pea) + opMFI(0xf5, read_dpr, sbc, X) + opMF (0xf6, adjust_dpx, inc) + opMF (0xf7, read_ildpy, sbc) + opAII(0xf8, flag, 0x08, 0x08) + opMF (0xf9, read_addry, sbc) + opXI (0xfa, pull, X) + opA (0xfb, xce) + opE (0xfc, jsr_iaddrx) + opMF (0xfd, read_addrx, sbc) + opMF (0xfe, adjust_addrx, inc) + opMF (0xff, read_longx, sbc) + + #undef opA + #undef opAII + #undef opE + #undef opEI + #undef opEII + #undef opM + #undef opMI + #undef opMII + #undef opMF + #undef opMFI + #undef opX + #undef opXI + #undef opXII + #undef opXF + #undef opXFI +} + +void CPUcore::update_table() { + if(regs.e) { + opcode_table = &op_table[table_EM]; + } else if(regs.p.m) { + if(regs.p.x) { + opcode_table = &op_table[table_MX]; + } else { + opcode_table = &op_table[table_Mx]; + } + } else { + if(regs.p.x) { + opcode_table = &op_table[table_mX]; + } else { + opcode_table = &op_table[table_mx]; + } + } +} + +#endif diff --git a/snes/cpu/cpu.cpp b/snes/cpu/cpu.cpp new file mode 100755 index 00000000..4e83429f --- /dev/null +++ b/snes/cpu/cpu.cpp @@ -0,0 +1,163 @@ +#include + +#define CPU_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + CPUDebugger cpu; +#else + CPU cpu; +#endif + +#include "serialization.cpp" +#include "dma/dma.cpp" +#include "memory/memory.cpp" +#include "mmio/mmio.cpp" +#include "timing/timing.cpp" + +void CPU::step(unsigned clocks) { + smp.clock -= clocks * (uint64)smp.frequency; + ppu.clock -= clocks; + for(unsigned i = 0; i < coprocessors.size(); i++) { + 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() { + if(SMP::Threaded == true) { + if(smp.clock < 0) co_switch(smp.thread); + } else { + while(smp.clock < 0) smp.enter(); + } +} + +void CPU::synchronize_ppu() { + if(PPU::Threaded == true) { + if(ppu.clock < 0) co_switch(ppu.thread); + } else { + while(ppu.clock < 0) ppu.enter(); + } +} + +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() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::CPU) { + scheduler.sync = Scheduler::SynchronizeMode::All; + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(status.interrupt_pending) { + status.interrupt_pending = false; + if(status.nmi_pending) { + status.nmi_pending = false; + regs.vector = (regs.e == false ? 0xffea : 0xfffa); + op_irq(); + } else if(status.irq_pending) { + status.irq_pending = false; + regs.vector = (regs.e == false ? 0xffee : 0xfffe); + op_irq(); + } else if(status.reset_pending) { + status.reset_pending = false; + add_clocks(186); + regs.pc.l = bus.read(0xfffc); + regs.pc.h = bus.read(0xfffd); + } + } + + op_step(); + } +} + +void CPU::op_step() { + (this->*opcode_table[op_readpc()])(); +} + +void CPU::enable() { + function read = { &CPU::mmio_read, (CPU*)&cpu }; + function write = { &CPU::mmio_write, (CPU*)&cpu }; + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write); + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write); + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write); + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write); + + read = [](unsigned addr) { return cpu.wram[addr]; }; + write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; }; + + bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000); + bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000); + bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write); +} + +void CPU::power() { + cpu_version = config.cpu.version; + for(auto &n : wram) n = random(config.cpu.wram_init_value); + + regs.a = regs.x = regs.y = 0x0000; + regs.s = 0x01ff; + + mmio_power(); + dma_power(); + timing_power(); + + reset(); +} + +void CPU::reset() { + create(Enter, system.cpu_frequency()); + coprocessors.reset(); + PPUcounter::reset(); + + //note: some registers are not fully reset by SNES + regs.pc = 0x000000; + regs.x.h = 0x00; + regs.y.h = 0x00; + regs.s.h = 0x01; + regs.d = 0x0000; + regs.db = 0x00; + regs.p = 0x34; + regs.e = 1; + regs.mdr = 0x00; + regs.wai = false; + regs.vector = 0xfffc; //reset vector address + update_table(); + + mmio_reset(); + dma_reset(); + timing_reset(); +} + +CPU::CPU() { + PPUcounter::scanline = { &CPU::scanline, this }; +} + +CPU::~CPU() { +} + +} diff --git a/snes/cpu/cpu.hpp b/snes/cpu/cpu.hpp new file mode 100755 index 00000000..67a56d14 --- /dev/null +++ b/snes/cpu/cpu.hpp @@ -0,0 +1,144 @@ +struct CPU : public Processor, public CPUcore, public PPUcounter { + uint8 wram[128 * 1024]; + + enum : bool { Threaded = true }; + array coprocessors; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_smp(); + void synchronize_ppu(); + void synchronize_coprocessors(); + void synchronize_controllers(); + + uint8 port_read(uint2 port) const; + void port_write(uint2 port, uint8 data); + + uint8 pio(); + bool joylatch(); + alwaysinline bool interrupt_pending() { return status.interrupt_pending; } + + void enter(); + void enable(); + void power(); + void reset(); + + void serialize(serializer&); + CPU(); + ~CPU(); + +private: + #include "dma/dma.hpp" + #include "memory/memory.hpp" + #include "mmio/mmio.hpp" + #include "timing/timing.hpp" + + uint8 cpu_version; + + struct Status { + bool interrupt_pending; + + unsigned clock_count; + unsigned line_clocks; + + //timing + bool irq_lock; + + unsigned dram_refresh_position; + bool dram_refreshed; + + unsigned hdma_init_position; + bool hdma_init_triggered; + + unsigned hdma_position; + bool hdma_triggered; + + bool nmi_valid; + bool nmi_line; + bool nmi_transition; + bool nmi_pending; + bool nmi_hold; + + bool irq_valid; + bool irq_line; + bool irq_transition; + bool irq_pending; + bool irq_hold; + + bool reset_pending; + + //DMA + bool dma_active; + unsigned dma_counter; + unsigned dma_clocks; + bool dma_pending; + bool hdma_pending; + bool hdma_mode; //0 = init, 1 = run + + //auto joypad polling + bool auto_joypad_active; + unsigned auto_joypad_counter; + unsigned auto_joypad_clock; + + //MMIO + //$2140-217f + uint8 port[4]; + + //$2181-$2183 + uint17 wram_addr; + + //$4016-$4017 + bool joypad_strobe_latch; + uint32 joypad1_bits; + uint32 joypad2_bits; + + //$4200 + bool nmi_enabled; + bool hirq_enabled, virq_enabled; + bool auto_joypad_poll; + + //$4201 + uint8 pio; + + //$4202-$4203 + uint8 wrmpya; + uint8 wrmpyb; + + //$4204-$4206 + uint16 wrdiva; + uint8 wrdivb; + + //$4207-$420a + uint9 hirq_pos; + uint9 virq_pos; + + //$420d + unsigned rom_speed; + + //$4214-$4217 + uint16 rddiv; + uint16 rdmpy; + + //$4218-$421f + uint16 joy1; + uint16 joy2; + uint16 joy3; + uint16 joy4; + } status; + + struct ALU { + unsigned mpyctr; + unsigned divctr; + unsigned shift; + } alu; + + static void Enter(); + debugvirtual void op_step(); + + friend class CPUDebugger; +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern CPUDebugger cpu; +#else + extern CPU cpu; +#endif diff --git a/snes/cpu/debugger/debugger.cpp b/snes/cpu/debugger/debugger.cpp new file mode 100755 index 00000000..a33518ed --- /dev/null +++ b/snes/cpu/debugger/debugger.cpp @@ -0,0 +1,156 @@ +#ifdef CPU_CPP + +void CPUDebugger::op_step() { + bool break_event = false; + + usage[regs.pc] &= ~(UsageFlagM | UsageFlagX); + usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0); + opcode_pc = regs.pc; + + opcode_edge = true; + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); + if(step_event && step_event() == true) { + debugger.break_event = Debugger::BreakEvent::CPUStep; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + } + opcode_edge = false; + + CPU::op_step(); + synchronize_smp(); +} + +uint8 CPUDebugger::op_read(uint32 addr) { + uint8 data = CPU::op_read(addr); + usage[addr] |= UsageRead; + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void CPUDebugger::op_write(uint32 addr, uint8 data) { + CPU::op_write(addr, data); + usage[addr] |= UsageWrite; + usage[addr] &= ~UsageExec; + debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Write, addr, data); +} + +CPUDebugger::CPUDebugger() { + usage = new uint8[1 << 24](); + opcode_pc = 0x8000; + opcode_edge = false; +} + +CPUDebugger::~CPUDebugger() { + delete[] usage; +} + +bool CPUDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //internal + item("S-CPU MDR", string("0x", hex<2>(regs.mdr))); + + //$2181-2183 + item("$2181-$2183", ""); + item("WRAM Address", string("0x", hex<6>(status.wram_addr))); + + //$4016 + item("$4016", ""); + item("Joypad Strobe Latch", status.joypad_strobe_latch); + + //$4200 + item("$4200", ""); + item("NMI Enable", status.nmi_enabled); + item("H-IRQ Enable", status.hirq_enabled); + item("V-IRQ Enable", status.virq_enabled); + item("Auto Joypad Poll", status.auto_joypad_poll); + + //$4201 + item("$4201", ""); + item("PIO", string("0x", hex<2>(status.pio))); + + //$4202 + item("$4202", ""); + item("Multiplicand", string("0x", hex<2>(status.wrmpya))); + + //$4203 + item("$4203", ""); + item("Multiplier", string("0x", hex<2>(status.wrmpyb))); + + //$4204-$4205 + item("$4204-$4205", ""); + item("Dividend", string("0x", hex<4>(status.wrdiva))); + + //$4206 + item("$4206", ""); + item("Divisor", string("0x", hex<2>(status.wrdivb))); + + //$4207-$4208 + item("$4207-$4208", ""); + item("H-Time", string("0x", hex<4>(status.hirq_pos))); + + //$4209-$420a + item("$4209-$420a", ""); + item("V-Time", string("0x", hex<4>(status.virq_pos))); + + //$420b + unsigned dma_enable = 0; + for(unsigned n = 0; n < 8; n++) dma_enable |= channel[n].dma_enabled << n; + + item("$420b", ""); + item("DMA Enable", string("0x", hex<2>(dma_enable))); + + //$420c + unsigned hdma_enable = 0; + for(unsigned n = 0; n < 8; n++) hdma_enable |= channel[n].hdma_enabled << n; + + item("$420c", ""); + item("HDMA Enable", string("0x", hex<2>(hdma_enable))); + + //$420d + item("$420d", ""); + item("FastROM Enable", status.rom_speed == 6); + + for(unsigned i = 0; i < 8; i++) { + item(string("DMA Channel ", i), ""); + + //$43x0 + item("Direction", channel[i].direction); + item("Indirect", channel[i].indirect); + item("Reverse Transfer", channel[i].reverse_transfer); + item("Fixed Transfer", channel[i].fixed_transfer); + item("Transfer Mode", (unsigned)channel[i].transfer_mode); + + //$43x1 + item("B-Bus Address", string("0x", hex<4>(channel[i].dest_addr))); + + //$43x2-$43x3 + item("A-Bus Address", string("0x", hex<4>(channel[i].source_addr))); + + //$43x4 + item("A-Bus Bank", string("0x", hex<2>(channel[i].source_bank))); + + //$43x5-$43x6 + item("Transfer Size / Indirect Address", string("0x", hex<4>(channel[i].transfer_size))); + + //$43x7 + item("Indirect Bank", string("0x", hex<2>(channel[i].indirect_bank))); + + //$43x8-$43x9 + item("Table Address", string("0x", hex<4>(channel[i].hdma_addr))); + + //$43xa + item("Line Counter", string("0x", hex<2>(channel[i].line_counter))); + } + + #undef item + return false; +} + +#endif diff --git a/snes/cpu/debugger/debugger.hpp b/snes/cpu/debugger/debugger.hpp new file mode 100755 index 00000000..579f6f03 --- /dev/null +++ b/snes/cpu/debugger/debugger.hpp @@ -0,0 +1,24 @@ +class CPUDebugger : public CPU, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + function step_event; + + enum Usage { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + UsageFlagM = 0x02, + UsageFlagX = 0x01, + }; + uint8 *usage; + uint24 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints + bool opcode_edge; //true right before an opcode execues, used to skip over opcodes + + void op_step(); + uint8 op_read(uint32 addr); + void op_write(uint32 addr, uint8 data); + + CPUDebugger(); + ~CPUDebugger(); +}; diff --git a/snes/cpu/dma/dma.cpp b/snes/cpu/dma/dma.cpp new file mode 100755 index 00000000..e8cdb3ec --- /dev/null +++ b/snes/cpu/dma/dma.cpp @@ -0,0 +1,289 @@ +#ifdef CPU_CPP + +void CPU::dma_add_clocks(unsigned clocks) { + status.dma_clocks += clocks; + add_clocks(clocks); +} + +//============= +//memory access +//============= + +bool CPU::dma_transfer_valid(uint8 bbus, uint32 abus) { + //transfers from WRAM to WRAM are invalid; chip only has one address bus + if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) return false; + return true; +} + +bool CPU::dma_addr_valid(uint32 abus) { + //A-bus access to B-bus or S-CPU registers are invalid + if((abus & 0x40ff00) == 0x2100) return false; //$[00-3f|80-bf]:[2100-21ff] + if((abus & 0x40fe00) == 0x4000) return false; //$[00-3f|80-bf]:[4000-41ff] + if((abus & 0x40ffe0) == 0x4200) return false; //$[00-3f|80-bf]:[4200-421f] + if((abus & 0x40ff80) == 0x4300) return false; //$[00-3f|80-bf]:[4300-437f] + return true; +} + +uint8 CPU::dma_read(uint32 abus) { + if(dma_addr_valid(abus) == false) return 0x00; + return bus.read(abus); +} + +//simulate two-stage pipeline for DMA transfers; example: +//cycle 0: read N+0 +//cycle 1: write N+0 & read N+1 (parallel; one on A-bus, one on B-bus) +//cycle 2: write N+1 & read N+2 (parallel) +//cycle 3: write N+2 +void CPU::dma_write(bool valid, unsigned addr, uint8 data) { + if(pipe.valid) bus.write(pipe.addr, pipe.data); + pipe.valid = valid; + pipe.addr = addr; + pipe.data = data; +} + +void CPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) { + if(direction == 0) { + dma_add_clocks(4); + regs.mdr = dma_read(abus); + dma_add_clocks(4); + dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, regs.mdr); + } else { + dma_add_clocks(4); + regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus) : 0x00; + dma_add_clocks(4); + dma_write(dma_addr_valid(abus), abus, regs.mdr); + } +} + +//=================== +//address calculation +//=================== + +uint8 CPU::dma_bbus(unsigned i, unsigned index) { + switch(channel[i].transfer_mode) { default: + case 0: return (channel[i].dest_addr); //0 + case 1: return (channel[i].dest_addr + (index & 1)); //0,1 + case 2: return (channel[i].dest_addr); //0,0 + case 3: return (channel[i].dest_addr + ((index >> 1) & 1)); //0,0,1,1 + case 4: return (channel[i].dest_addr + (index & 3)); //0,1,2,3 + case 5: return (channel[i].dest_addr + (index & 1)); //0,1,0,1 + case 6: return (channel[i].dest_addr); //0,0 [2] + case 7: return (channel[i].dest_addr + ((index >> 1) & 1)); //0,0,1,1 [3] + } +} + +inline uint32 CPU::dma_addr(unsigned i) { + uint32 r = (channel[i].source_bank << 16) | (channel[i].source_addr); + + if(channel[i].fixed_transfer == false) { + if(channel[i].reverse_transfer == false) { + channel[i].source_addr++; + } else { + channel[i].source_addr--; + } + } + + return r; +} + +inline uint32 CPU::hdma_addr(unsigned i) { + return (channel[i].source_bank << 16) | (channel[i].hdma_addr++); +} + +inline uint32 CPU::hdma_iaddr(unsigned i) { + return (channel[i].indirect_bank << 16) | (channel[i].indirect_addr++); +} + +//============== +//channel status +//============== + +uint8 CPU::dma_enabled_channels() { + uint8 r = 0; + for(unsigned i = 0; i < 8; i++) { + if(channel[i].dma_enabled) r++; + } + return r; +} + +inline bool CPU::hdma_active(unsigned i) { + return (channel[i].hdma_enabled && !channel[i].hdma_completed); +} + +inline bool CPU::hdma_active_after(unsigned i) { + for(unsigned n = i + 1; n < 8; n++) { + if(hdma_active(n) == true) return true; + } + return false; +} + +inline uint8 CPU::hdma_enabled_channels() { + uint8 r = 0; + for(unsigned i = 0; i < 8; i++) { + if(channel[i].hdma_enabled) r++; + } + return r; +} + +inline uint8 CPU::hdma_active_channels() { + uint8 r = 0; + for(unsigned i = 0; i < 8; i++) { + if(hdma_active(i) == true) r++; + } + return r; +} + +//============== +//core functions +//============== + +void CPU::dma_run() { + dma_add_clocks(8); + dma_write(false); + dma_edge(); + + for(unsigned i = 0; i < 8; i++) { + if(channel[i].dma_enabled == false) continue; + + unsigned index = 0; + do { + dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i)); + dma_edge(); + } while(channel[i].dma_enabled && --channel[i].transfer_size); + + dma_add_clocks(8); + dma_write(false); + dma_edge(); + + channel[i].dma_enabled = false; + } + + status.irq_lock = true; +} + +void CPU::hdma_update(unsigned i) { + dma_add_clocks(4); + regs.mdr = dma_read((channel[i].source_bank << 16) | channel[i].hdma_addr); + dma_add_clocks(4); + dma_write(false); + + if((channel[i].line_counter & 0x7f) == 0) { + channel[i].line_counter = regs.mdr; + channel[i].hdma_addr++; + + channel[i].hdma_completed = (channel[i].line_counter == 0); + channel[i].hdma_do_transfer = !channel[i].hdma_completed; + + if(channel[i].indirect) { + dma_add_clocks(4); + regs.mdr = dma_read(hdma_addr(i)); + channel[i].indirect_addr = regs.mdr << 8; + dma_add_clocks(4); + dma_write(false); + + if(!channel[i].hdma_completed || hdma_active_after(i)) { + dma_add_clocks(4); + regs.mdr = dma_read(hdma_addr(i)); + channel[i].indirect_addr >>= 8; + channel[i].indirect_addr |= regs.mdr << 8; + dma_add_clocks(4); + dma_write(false); + } + } + } +} + +void CPU::hdma_run() { + dma_add_clocks(8); + dma_write(false); + + for(unsigned i = 0; i < 8; i++) { + if(hdma_active(i) == false) continue; + channel[i].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer + + if(channel[i].hdma_do_transfer) { + static const unsigned transfer_length[8] = { 1, 2, 2, 4, 4, 4, 2, 4 }; + unsigned length = transfer_length[channel[i].transfer_mode]; + for(unsigned index = 0; index < length; index++) { + unsigned addr = channel[i].indirect == false ? hdma_addr(i) : hdma_iaddr(i); + dma_transfer(channel[i].direction, dma_bbus(i, index), addr); + } + } + } + + for(unsigned i = 0; i < 8; i++) { + if(hdma_active(i) == false) continue; + + channel[i].line_counter--; + channel[i].hdma_do_transfer = channel[i].line_counter & 0x80; + hdma_update(i); + } + + status.irq_lock = true; +} + +void CPU::hdma_init_reset() { + for(unsigned i = 0; i < 8; i++) { + channel[i].hdma_completed = false; + channel[i].hdma_do_transfer = false; + } +} + +void CPU::hdma_init() { + dma_add_clocks(8); + dma_write(false); + + for(unsigned i = 0; i < 8; i++) { + if(!channel[i].hdma_enabled) continue; + channel[i].dma_enabled = false; //HDMA init during DMA will stop DMA mid-transfer + + channel[i].hdma_addr = channel[i].source_addr; + channel[i].line_counter = 0; + hdma_update(i); + } + + status.irq_lock = true; +} + +//============== +//initialization +//============== + +void CPU::dma_power() { + for(unsigned i = 0; i < 8; i++) { + channel[i].direction = 1; + channel[i].indirect = true; + channel[i].unused = true; + channel[i].reverse_transfer = true; + channel[i].fixed_transfer = true; + channel[i].transfer_mode = 7; + + channel[i].dest_addr = 0xff; + + channel[i].source_addr = 0xffff; + channel[i].source_bank = 0xff; + + channel[i].transfer_size = 0xffff; + channel[i].indirect_bank = 0xff; + + channel[i].hdma_addr = 0xffff; + channel[i].line_counter = 0xff; + channel[i].unknown = 0xff; + } +} + +void CPU::dma_reset() { + for(unsigned i = 0; i < 8; i++) { + channel[i].dma_enabled = false; + channel[i].hdma_enabled = false; + + channel[i].hdma_completed = false; + channel[i].hdma_do_transfer = false; + } + + pipe.valid = false; + pipe.addr = 0; + pipe.data = 0; +} + +#endif diff --git a/snes/cpu/dma/dma.hpp b/snes/cpu/dma/dma.hpp new file mode 100755 index 00000000..33755bde --- /dev/null +++ b/snes/cpu/dma/dma.hpp @@ -0,0 +1,79 @@ +struct { + //$420b + bool dma_enabled; + + //$420c + bool hdma_enabled; + + //$43x0 + bool direction; + bool indirect; + bool unused; + bool reverse_transfer; + bool fixed_transfer; + uint3 transfer_mode; + + //$43x1 + uint8 dest_addr; + + //$43x2-$43x3 + uint16 source_addr; + + //$43x4 + uint8 source_bank; + + //$43x5-$43x6 + union { + uint16 transfer_size; + uint16 indirect_addr; + }; + + //$43x7 + uint8 indirect_bank; + + //$43x8-$43x9 + uint16 hdma_addr; + + //$43xa + uint8 line_counter; + + //$43xb/$43xf + uint8 unknown; + + //internal state + bool hdma_completed; + bool hdma_do_transfer; +} channel[8]; + +struct { + bool valid; + unsigned addr; + uint8 data; +} pipe; + +void dma_add_clocks(unsigned clocks); +bool dma_transfer_valid(uint8 bbus, uint32 abus); +bool dma_addr_valid(uint32 abus); +uint8 dma_read(uint32 abus); +void dma_write(bool valid, unsigned addr = 0, uint8 data = 0); +void dma_transfer(bool direction, uint8 bbus, uint32 abus); + +uint8 dma_bbus(unsigned i, unsigned channel); +uint32 dma_addr(unsigned i); +uint32 hdma_addr(unsigned i); +uint32 hdma_iaddr(unsigned i); + +uint8 dma_enabled_channels(); +bool hdma_active(unsigned i); +bool hdma_active_after(unsigned i); +uint8 hdma_enabled_channels(); +uint8 hdma_active_channels(); + +void dma_run(); +void hdma_update(unsigned i); +void hdma_run(); +void hdma_init_reset(); +void hdma_init(); + +void dma_power(); +void dma_reset(); diff --git a/snes/cpu/memory/memory.cpp b/snes/cpu/memory/memory.cpp new file mode 100755 index 00000000..c2c8f1fa --- /dev/null +++ b/snes/cpu/memory/memory.cpp @@ -0,0 +1,41 @@ +#ifdef CPU_CPP + +uint8 CPU::port_read(uint2 port) const { return status.port[port]; } +void CPU::port_write(uint2 port, uint8 data) { status.port[port] = data; } + +void CPU::op_io() { + status.clock_count = 6; + dma_edge(); + add_clocks(6); + alu_edge(); +} + +uint8 CPU::op_read(uint32 addr) { + status.clock_count = speed(addr); + dma_edge(); + add_clocks(status.clock_count - 4); + regs.mdr = bus.read(addr); + add_clocks(4); + alu_edge(); + return regs.mdr; +} + +void CPU::op_write(uint32 addr, uint8 data) { + alu_edge(); + status.clock_count = speed(addr); + dma_edge(); + add_clocks(status.clock_count); + bus.write(addr, regs.mdr = data); +} + +unsigned CPU::speed(unsigned addr) const { + if(addr & 0x408000) { + if(addr & 0x800000) return status.rom_speed; + return 8; + } + if((addr + 0x6000) & 0x4000) return 8; + if((addr - 0x4000) & 0x7e00) return 6; + return 12; +} + +#endif diff --git a/snes/cpu/memory/memory.hpp b/snes/cpu/memory/memory.hpp new file mode 100755 index 00000000..d33861d4 --- /dev/null +++ b/snes/cpu/memory/memory.hpp @@ -0,0 +1,4 @@ +void op_io(); +debugvirtual uint8 op_read(uint32 addr); +debugvirtual void op_write(uint32 addr, uint8 data); +alwaysinline unsigned speed(unsigned addr) const; diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp new file mode 100755 index 00000000..8b6aaa6a --- /dev/null +++ b/snes/cpu/mmio/mmio.cpp @@ -0,0 +1,519 @@ +#ifdef CPU_CPP + +uint8 CPU::pio() { return status.pio; } +bool CPU::joylatch() { return status.joypad_strobe_latch; } + +//WMDATA +uint8 CPU::mmio_r2180() { + return bus.read(0x7e0000 | status.wram_addr++); +} + +//WMDATA +void CPU::mmio_w2180(uint8 data) { + bus.write(0x7e0000 | status.wram_addr++, data); +} + +//WMADDL +void CPU::mmio_w2181(uint8 data) { + status.wram_addr = (status.wram_addr & 0x01ff00) | (data << 0); +} + +//WMADDM +void CPU::mmio_w2182(uint8 data) { + status.wram_addr = (status.wram_addr & 0x0100ff) | (data << 8); +} + +//WMADDH +void CPU::mmio_w2183(uint8 data) { + status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16); +} + +//JOYSER0 +//bit 0 is shared between JOYSER0 and JOYSER1, therefore +//strobing $4016.d0 affects both controller port latches. +//$4017 bit 0 writes are ignored. +void CPU::mmio_w4016(uint8 data) { + input.port1->latch(data & 1); + input.port2->latch(data & 1); +} + +//JOYSER0 +//7-2 = MDR +//1-0 = Joypad serial data +uint8 CPU::mmio_r4016() { + uint8 r = regs.mdr & 0xfc; + r |= input.port1->data(); + return r; +} + +//JOYSER1 +//7-5 = MDR +//4-2 = Always 1 (pins are connected to GND) +//1-0 = Joypad serial data +uint8 CPU::mmio_r4017() { + uint8 r = (regs.mdr & 0xe0) | 0x1c; + r |= input.port2->data(); + return r; +} + +//NMITIMEN +void CPU::mmio_w4200(uint8 data) { + status.auto_joypad_poll = data & 1; + nmitimen_update(data); +} + +//WRIO +void CPU::mmio_w4201(uint8 data) { + if((status.pio & 0x80) && !(data & 0x80)) ppu.latch_counters(); + status.pio = data; +} + +//WRMPYA +void CPU::mmio_w4202(uint8 data) { + status.wrmpya = data; +} + +//WRMPYB +void CPU::mmio_w4203(uint8 data) { + status.rdmpy = 0; + if(alu.mpyctr || alu.divctr) return; + + status.wrmpyb = data; + status.rddiv = (status.wrmpyb << 8) | status.wrmpya; + + alu.mpyctr = 8; //perform multiplication over the next eight cycles + alu.shift = status.wrmpyb; +} + +//WRDIVL +void CPU::mmio_w4204(uint8 data) { + status.wrdiva = (status.wrdiva & 0xff00) | (data << 0); +} + +//WRDIVH +void CPU::mmio_w4205(uint8 data) { + status.wrdiva = (status.wrdiva & 0x00ff) | (data << 8); +} + +//WRDIVB +void CPU::mmio_w4206(uint8 data) { + status.rdmpy = status.wrdiva; + if(alu.mpyctr || alu.divctr) return; + + status.wrdivb = data; + + alu.divctr = 16; //perform division over the next sixteen cycles + alu.shift = status.wrdivb << 16; +} + +//HTIMEL +void CPU::mmio_w4207(uint8 data) { + status.hirq_pos = (status.hirq_pos & 0x0100) | (data << 0); +} + +//HTIMEH +void CPU::mmio_w4208(uint8 data) { + status.hirq_pos = (status.hirq_pos & 0x00ff) | (data << 8); +} + +//VTIMEL +void CPU::mmio_w4209(uint8 data) { + status.virq_pos = (status.virq_pos & 0x0100) | (data << 0); +} + +//VTIMEH +void CPU::mmio_w420a(uint8 data) { + status.virq_pos = (status.virq_pos & 0x00ff) | (data << 8); +} + +//DMAEN +void CPU::mmio_w420b(uint8 data) { + for(unsigned i = 0; i < 8; i++) { + channel[i].dma_enabled = data & (1 << i); + } + if(data) status.dma_pending = true; +} + +//HDMAEN +void CPU::mmio_w420c(uint8 data) { + for(unsigned i = 0; i < 8; i++) { + channel[i].hdma_enabled = data & (1 << i); + } +} + +//MEMSEL +void CPU::mmio_w420d(uint8 data) { + status.rom_speed = (data & 1 ? 6 : 8); +} + +//RDNMI +//7 = NMI acknowledge +//6-4 = MDR +//3-0 = CPU (5a22) version +uint8 CPU::mmio_r4210() { + uint8 r = (regs.mdr & 0x70); + r |= (uint8)(rdnmi()) << 7; + r |= (cpu_version & 0x0f); + return r; +} + +//TIMEUP +//7 = IRQ acknowledge +//6-0 = MDR +uint8 CPU::mmio_r4211() { + uint8 r = (regs.mdr & 0x7f); + r |= (uint8)(timeup()) << 7; + return r; +} + +//HVBJOY +//7 = VBLANK acknowledge +//6 = HBLANK acknowledge +//5-1 = MDR +//0 = JOYPAD acknowledge +uint8 CPU::mmio_r4212() { + uint8 r = (regs.mdr & 0x3e); + if(status.auto_joypad_active) r |= 0x01; + if(hcounter() <= 2 || hcounter() >= 1096) r |= 0x40; //hblank + if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) r |= 0x80; //vblank + return r; +} + +//RDIO +uint8 CPU::mmio_r4213() { + return status.pio; +} + +//RDDIVL +uint8 CPU::mmio_r4214() { + return status.rddiv >> 0; +} + +//RDDIVH +uint8 CPU::mmio_r4215() { + return status.rddiv >> 8; +} + +//RDMPYL +uint8 CPU::mmio_r4216() { + return status.rdmpy >> 0; +} + +//RDMPYH +uint8 CPU::mmio_r4217() { + return status.rdmpy >> 8; +} + +uint8 CPU::mmio_r4218() { return status.joy1 >> 0; } //JOY1L +uint8 CPU::mmio_r4219() { return status.joy1 >> 8; } //JOY1H +uint8 CPU::mmio_r421a() { return status.joy2 >> 0; } //JOY2L +uint8 CPU::mmio_r421b() { return status.joy2 >> 8; } //JOY2H +uint8 CPU::mmio_r421c() { return status.joy3 >> 0; } //JOY3L +uint8 CPU::mmio_r421d() { return status.joy3 >> 8; } //JOY3H +uint8 CPU::mmio_r421e() { return status.joy4 >> 0; } //JOY4L +uint8 CPU::mmio_r421f() { return status.joy4 >> 8; } //JOY4H + +//DMAPx +uint8 CPU::mmio_r43x0(uint8 i) { + return (channel[i].direction << 7) + | (channel[i].indirect << 6) + | (channel[i].unused << 5) + | (channel[i].reverse_transfer << 4) + | (channel[i].fixed_transfer << 3) + | (channel[i].transfer_mode << 0); +} + +//BBADx +uint8 CPU::mmio_r43x1(uint8 i) { + return channel[i].dest_addr; +} + +//A1TxL +uint8 CPU::mmio_r43x2(uint8 i) { + return channel[i].source_addr >> 0; +} + +//A1TxH +uint8 CPU::mmio_r43x3(uint8 i) { + return channel[i].source_addr >> 8; +} + +//A1Bx +uint8 CPU::mmio_r43x4(uint8 i) { + return channel[i].source_bank; +} + +//DASxL +//union { uint16 transfer_size; uint16 indirect_addr; }; +uint8 CPU::mmio_r43x5(uint8 i) { + return channel[i].transfer_size >> 0; +} + +//DASxH +//union { uint16 transfer_size; uint16 indirect_addr; }; +uint8 CPU::mmio_r43x6(uint8 i) { + return channel[i].transfer_size >> 8; +} + +//DASBx +uint8 CPU::mmio_r43x7(uint8 i) { + return channel[i].indirect_bank; +} + +//A2AxL +uint8 CPU::mmio_r43x8(uint8 i) { + return channel[i].hdma_addr >> 0; +} + +//A2AxH +uint8 CPU::mmio_r43x9(uint8 i) { + return channel[i].hdma_addr >> 8; +} + +//NTRLx +uint8 CPU::mmio_r43xa(uint8 i) { + return channel[i].line_counter; +} + +//??? +uint8 CPU::mmio_r43xb(uint8 i) { + return channel[i].unknown; +} + +//DMAPx +void CPU::mmio_w43x0(uint8 i, uint8 data) { + channel[i].direction = data & 0x80; + channel[i].indirect = data & 0x40; + channel[i].unused = data & 0x20; + channel[i].reverse_transfer = data & 0x10; + channel[i].fixed_transfer = data & 0x08; + channel[i].transfer_mode = data & 0x07; +} + +//DDBADx +void CPU::mmio_w43x1(uint8 i, uint8 data) { + channel[i].dest_addr = data; +} + +//A1TxL +void CPU::mmio_w43x2(uint8 i, uint8 data) { + channel[i].source_addr = (channel[i].source_addr & 0xff00) | (data << 0); +} + +//A1TxH +void CPU::mmio_w43x3(uint8 i, uint8 data) { + channel[i].source_addr = (channel[i].source_addr & 0x00ff) | (data << 8); +} + +//A1Bx +void CPU::mmio_w43x4(uint8 i, uint8 data) { + channel[i].source_bank = data; +} + +//DASxL +//union { uint16 transfer_size; uint16 indirect_addr; }; +void CPU::mmio_w43x5(uint8 i, uint8 data) { + channel[i].transfer_size = (channel[i].transfer_size & 0xff00) | (data << 0); +} + +//DASxH +//union { uint16 transfer_size; uint16 indirect_addr; }; +void CPU::mmio_w43x6(uint8 i, uint8 data) { + channel[i].transfer_size = (channel[i].transfer_size & 0x00ff) | (data << 8); +} + +//DASBx +void CPU::mmio_w43x7(uint8 i, uint8 data) { + channel[i].indirect_bank = data; +} + +//A2AxL +void CPU::mmio_w43x8(uint8 i, uint8 data) { + channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data << 0); +} + +//A2AxH +void CPU::mmio_w43x9(uint8 i, uint8 data) { + channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8); +} + +//NTRLx +void CPU::mmio_w43xa(uint8 i, uint8 data) { + channel[i].line_counter = data; +} + +//??? +void CPU::mmio_w43xb(uint8 i, uint8 data) { + channel[i].unknown = data; +} + +void CPU::mmio_power() { +} + +void CPU::mmio_reset() { + //$2140-217f + for(auto &port : status.port) port = 0x00; + + //$2181-$2183 + status.wram_addr = 0x000000; + + //$4016-$4017 + status.joypad_strobe_latch = 0; + status.joypad1_bits = ~0; + status.joypad2_bits = ~0; + + //$4200 + status.nmi_enabled = false; + status.hirq_enabled = false; + status.virq_enabled = false; + status.auto_joypad_poll = false; + + //$4201 + status.pio = 0xff; + + //$4202-$4203 + status.wrmpya = 0xff; + status.wrmpyb = 0xff; + + //$4204-$4206 + status.wrdiva = 0xffff; + status.wrdivb = 0xff; + + //$4207-$420a + status.hirq_pos = 0x01ff; + status.virq_pos = 0x01ff; + + //$420d + status.rom_speed = 8; + + //$4214-$4217 + status.rddiv = 0x0000; + status.rdmpy = 0x0000; + + //$4218-$421f + status.joy1 = 0x0000; + status.joy2 = 0x0000; + status.joy3 = 0x0000; + status.joy4 = 0x0000; + + //ALU + alu.mpyctr = 0; + alu.divctr = 0; + alu.shift = 0; +} + +uint8 CPU::mmio_read(unsigned addr) { + addr &= 0xffff; + + //APU + if((addr & 0xffc0) == 0x2140) { //$2140-$217f + synchronize_smp(); + return smp.port_read(addr); + } + + //DMA + if((addr & 0xff80) == 0x4300) { //$4300-$437f + unsigned i = (addr >> 4) & 7; + switch(addr & 0xf) { + case 0x0: return mmio_r43x0(i); + case 0x1: return mmio_r43x1(i); + case 0x2: return mmio_r43x2(i); + case 0x3: return mmio_r43x3(i); + case 0x4: return mmio_r43x4(i); + case 0x5: return mmio_r43x5(i); + case 0x6: return mmio_r43x6(i); + case 0x7: return mmio_r43x7(i); + case 0x8: return mmio_r43x8(i); + case 0x9: return mmio_r43x9(i); + case 0xa: return mmio_r43xa(i); + case 0xb: return mmio_r43xb(i); + case 0xc: return regs.mdr; //unmapped + case 0xd: return regs.mdr; //unmapped + case 0xe: return regs.mdr; //unmapped + case 0xf: return mmio_r43xb(i); //mirror of $43xb + } + } + + switch(addr) { + case 0x2180: return mmio_r2180(); + case 0x4016: return mmio_r4016(); + case 0x4017: return mmio_r4017(); + case 0x4210: return mmio_r4210(); + case 0x4211: return mmio_r4211(); + case 0x4212: return mmio_r4212(); + case 0x4213: return mmio_r4213(); + case 0x4214: return mmio_r4214(); + case 0x4215: return mmio_r4215(); + case 0x4216: return mmio_r4216(); + case 0x4217: return mmio_r4217(); + case 0x4218: return mmio_r4218(); + case 0x4219: return mmio_r4219(); + case 0x421a: return mmio_r421a(); + case 0x421b: return mmio_r421b(); + case 0x421c: return mmio_r421c(); + case 0x421d: return mmio_r421d(); + case 0x421e: return mmio_r421e(); + case 0x421f: return mmio_r421f(); + } + + return regs.mdr; +} + +void CPU::mmio_write(unsigned addr, uint8 data) { + addr &= 0xffff; + + //APU + if((addr & 0xffc0) == 0x2140) { //$2140-$217f + synchronize_smp(); + port_write(addr, data); + return; + } + + //DMA + if((addr & 0xff80) == 0x4300) { //$4300-$437f + unsigned i = (addr >> 4) & 7; + switch(addr & 0xf) { + case 0x0: mmio_w43x0(i, data); return; + case 0x1: mmio_w43x1(i, data); return; + case 0x2: mmio_w43x2(i, data); return; + case 0x3: mmio_w43x3(i, data); return; + case 0x4: mmio_w43x4(i, data); return; + case 0x5: mmio_w43x5(i, data); return; + case 0x6: mmio_w43x6(i, data); return; + case 0x7: mmio_w43x7(i, data); return; + case 0x8: mmio_w43x8(i, data); return; + case 0x9: mmio_w43x9(i, data); return; + case 0xa: mmio_w43xa(i, data); return; + case 0xb: mmio_w43xb(i, data); return; + case 0xc: return; //unmapped + case 0xd: return; //unmapped + case 0xe: return; //unmapped + case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb + } + } + + switch(addr) { + case 0x2180: mmio_w2180(data); return; + case 0x2181: mmio_w2181(data); return; + case 0x2182: mmio_w2182(data); return; + case 0x2183: mmio_w2183(data); return; + case 0x4016: mmio_w4016(data); return; + case 0x4017: return; //unmapped + case 0x4200: mmio_w4200(data); return; + case 0x4201: mmio_w4201(data); return; + case 0x4202: mmio_w4202(data); return; + case 0x4203: mmio_w4203(data); return; + case 0x4204: mmio_w4204(data); return; + case 0x4205: mmio_w4205(data); return; + case 0x4206: mmio_w4206(data); return; + case 0x4207: mmio_w4207(data); return; + case 0x4208: mmio_w4208(data); return; + case 0x4209: mmio_w4209(data); return; + case 0x420a: mmio_w420a(data); return; + case 0x420b: mmio_w420b(data); return; + case 0x420c: mmio_w420c(data); return; + case 0x420d: mmio_w420d(data); return; + } +} + +#endif diff --git a/snes/cpu/mmio/mmio.hpp b/snes/cpu/mmio/mmio.hpp new file mode 100755 index 00000000..01cb2d1d --- /dev/null +++ b/snes/cpu/mmio/mmio.hpp @@ -0,0 +1,71 @@ +public: +uint8 mmio_read(unsigned addr); +void mmio_write(unsigned addr, uint8 data); + +private: +void mmio_power(); +void mmio_reset(); + +uint8 mmio_r2180(); +uint8 mmio_r4016(); +uint8 mmio_r4017(); +uint8 mmio_r4210(); +uint8 mmio_r4211(); +uint8 mmio_r4212(); +uint8 mmio_r4213(); +uint8 mmio_r4214(); +uint8 mmio_r4215(); +uint8 mmio_r4216(); +uint8 mmio_r4217(); +uint8 mmio_r4218(); +uint8 mmio_r4219(); +uint8 mmio_r421a(); +uint8 mmio_r421b(); +uint8 mmio_r421c(); +uint8 mmio_r421d(); +uint8 mmio_r421e(); +uint8 mmio_r421f(); +uint8 mmio_r43x0(uint8 i); +uint8 mmio_r43x1(uint8 i); +uint8 mmio_r43x2(uint8 i); +uint8 mmio_r43x3(uint8 i); +uint8 mmio_r43x4(uint8 i); +uint8 mmio_r43x5(uint8 i); +uint8 mmio_r43x6(uint8 i); +uint8 mmio_r43x7(uint8 i); +uint8 mmio_r43x8(uint8 i); +uint8 mmio_r43x9(uint8 i); +uint8 mmio_r43xa(uint8 i); +uint8 mmio_r43xb(uint8 i); + +void mmio_w2180(uint8 data); +void mmio_w2181(uint8 data); +void mmio_w2182(uint8 data); +void mmio_w2183(uint8 data); +void mmio_w4016(uint8 data); +void mmio_w4200(uint8 data); +void mmio_w4201(uint8 data); +void mmio_w4202(uint8 data); +void mmio_w4203(uint8 data); +void mmio_w4204(uint8 data); +void mmio_w4205(uint8 data); +void mmio_w4206(uint8 data); +void mmio_w4207(uint8 data); +void mmio_w4208(uint8 data); +void mmio_w4209(uint8 data); +void mmio_w420a(uint8 data); +void mmio_w420b(uint8 data); +void mmio_w420c(uint8 data); +void mmio_w420d(uint8 data); +void mmio_w43x0(uint8 i, uint8 data); +void mmio_w43x1(uint8 i, uint8 data); +void mmio_w43x2(uint8 i, uint8 data); +void mmio_w43x3(uint8 i, uint8 data); +void mmio_w43x4(uint8 i, uint8 data); +void mmio_w43x5(uint8 i, uint8 data); +void mmio_w43x6(uint8 i, uint8 data); +void mmio_w43x7(uint8 i, uint8 data); +void mmio_w43x8(uint8 i, uint8 data); +void mmio_w43x9(uint8 i, uint8 data); +void mmio_w43xa(uint8 i, uint8 data); +void mmio_w43xb(uint8 i, uint8 data); diff --git a/snes/cpu/serialization.cpp b/snes/cpu/serialization.cpp new file mode 100755 index 00000000..7a3367a2 --- /dev/null +++ b/snes/cpu/serialization.cpp @@ -0,0 +1,117 @@ +#ifdef CPU_CPP + +void CPU::serialize(serializer &s) { + Processor::serialize(s); + CPUcore::core_serialize(s); + PPUcounter::serialize(s); + + s.array(wram); + + s.integer(cpu_version); + + s.integer(status.interrupt_pending); + + s.integer(status.clock_count); + s.integer(status.line_clocks); + + s.integer(status.irq_lock); + + s.integer(status.dram_refresh_position); + s.integer(status.dram_refreshed); + + s.integer(status.hdma_init_position); + s.integer(status.hdma_init_triggered); + + s.integer(status.hdma_position); + s.integer(status.hdma_triggered); + + s.integer(status.nmi_valid); + s.integer(status.nmi_line); + s.integer(status.nmi_transition); + s.integer(status.nmi_pending); + s.integer(status.nmi_hold); + + s.integer(status.irq_valid); + s.integer(status.irq_line); + s.integer(status.irq_transition); + s.integer(status.irq_pending); + s.integer(status.irq_hold); + + s.integer(status.reset_pending); + + s.integer(status.dma_active); + s.integer(status.dma_counter); + s.integer(status.dma_clocks); + s.integer(status.dma_pending); + s.integer(status.hdma_pending); + s.integer(status.hdma_mode); + + s.integer(status.auto_joypad_active); + s.integer(status.auto_joypad_counter); + s.integer(status.auto_joypad_clock); + + s.array(status.port); + + s.integer(status.wram_addr); + + s.integer(status.joypad_strobe_latch); + s.integer(status.joypad1_bits); + s.integer(status.joypad2_bits); + + s.integer(status.nmi_enabled); + s.integer(status.hirq_enabled); + s.integer(status.virq_enabled); + s.integer(status.auto_joypad_poll); + + s.integer(status.pio); + + s.integer(status.wrmpya); + s.integer(status.wrmpyb); + + s.integer(status.wrdiva); + s.integer(status.wrdivb); + + s.integer(status.hirq_pos); + s.integer(status.virq_pos); + + s.integer(status.rom_speed); + + s.integer(status.rddiv); + s.integer(status.rdmpy); + + s.integer(status.joy1); + s.integer(status.joy2); + s.integer(status.joy3); + s.integer(status.joy4); + + s.integer(alu.mpyctr); + s.integer(alu.divctr); + s.integer(alu.shift); + + for(unsigned i = 0; i < 8; i++) { + s.integer(channel[i].dma_enabled); + s.integer(channel[i].hdma_enabled); + s.integer(channel[i].direction); + s.integer(channel[i].indirect); + s.integer(channel[i].unused); + s.integer(channel[i].reverse_transfer); + s.integer(channel[i].fixed_transfer); + s.integer(channel[i].transfer_mode); + s.integer(channel[i].dest_addr); + s.integer(channel[i].source_addr); + s.integer(channel[i].source_bank); + s.integer(channel[i].transfer_size); + s.integer(channel[i].indirect_bank); + s.integer(channel[i].hdma_addr); + s.integer(channel[i].line_counter); + s.integer(channel[i].unknown); + s.integer(channel[i].hdma_completed); + s.integer(channel[i].hdma_do_transfer); + } + + s.integer(pipe.valid); + s.integer(pipe.addr); + s.integer(pipe.data); +} + +#endif diff --git a/snes/cpu/timing/irq.cpp b/snes/cpu/timing/irq.cpp new file mode 100755 index 00000000..506a435e --- /dev/null +++ b/snes/cpu/timing/irq.cpp @@ -0,0 +1,106 @@ +#ifdef CPU_CPP + +//called once every four clock cycles; +//as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots. +// +//ppu.(vh)counter(n) returns the value of said counters n-clocks before current time; +//it is used to emulate hardware communication delay between opcode and interrupt units. +void CPU::poll_interrupts() { + //NMI hold + if(status.nmi_hold) { + status.nmi_hold = false; + if(status.nmi_enabled) status.nmi_transition = true; + } + + //NMI test + bool nmi_valid = (vcounter(2) >= (!ppu.overscan() ? 225 : 240)); + if(!status.nmi_valid && nmi_valid) { + //0->1 edge sensitive transition + status.nmi_line = true; + status.nmi_hold = true; //hold /NMI for four cycles + } else if(status.nmi_valid && !nmi_valid) { + //1->0 edge sensitive transition + status.nmi_line = false; + } + status.nmi_valid = nmi_valid; + + //IRQ hold + status.irq_hold = false; + if(status.irq_line) { + if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true; + } + + //IRQ test + bool irq_valid = (status.virq_enabled || status.hirq_enabled); + if(irq_valid) { + if((status.virq_enabled && vcounter(10) != (status.virq_pos)) + || (status.hirq_enabled && hcounter(10) != (status.hirq_pos + 1) * 4) + || (status.virq_pos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field + ) irq_valid = false; + } + if(!status.irq_valid && irq_valid) { + //0->1 edge sensitive transition + status.irq_line = true; + status.irq_hold = true; //hold /IRQ for four cycles + } + status.irq_valid = irq_valid; +} + +void CPU::nmitimen_update(uint8 data) { + bool nmi_enabled = status.nmi_enabled; + bool virq_enabled = status.virq_enabled; + bool hirq_enabled = status.hirq_enabled; + status.nmi_enabled = data & 0x80; + status.virq_enabled = data & 0x20; + status.hirq_enabled = data & 0x10; + + //0->1 edge sensitive transition + if(!nmi_enabled && status.nmi_enabled && status.nmi_line) { + status.nmi_transition = true; + } + + //?->1 level sensitive transition + if(status.virq_enabled && !status.hirq_enabled && status.irq_line) { + status.irq_transition = true; + } + + if(!status.virq_enabled && !status.hirq_enabled) { + status.irq_line = false; + status.irq_transition = false; + } + + status.irq_lock = true; +} + +bool CPU::rdnmi() { + bool result = status.nmi_line; + if(!status.nmi_hold) { + status.nmi_line = false; + } + return result; +} + +bool CPU::timeup() { + bool result = status.irq_line; + if(!status.irq_hold) { + status.irq_line = false; + status.irq_transition = false; + } + return result; +} + +bool CPU::nmi_test() { + if(!status.nmi_transition) return false; + status.nmi_transition = false; + regs.wai = false; + return true; +} + +bool CPU::irq_test() { + if(!status.irq_transition && !regs.irq) return false; + status.irq_transition = false; + regs.wai = false; + return !regs.p.i; +} + +#endif diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp new file mode 100755 index 00000000..6e15346e --- /dev/null +++ b/snes/cpu/timing/joypad.cpp @@ -0,0 +1,29 @@ +#ifdef CPU_CPP + +//called every 256 clocks; see CPU::add_clocks() +void CPU::step_auto_joypad_poll() { + if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) { + 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.port1->latch(1); + input.port2->latch(1); + input.port1->latch(0); + input.port2->latch(0); + } + + 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); + status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2); + status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2); + } + + status.auto_joypad_counter++; + } +} + +#endif diff --git a/snes/cpu/timing/timing.cpp b/snes/cpu/timing/timing.cpp new file mode 100755 index 00000000..0a80f299 --- /dev/null +++ b/snes/cpu/timing/timing.cpp @@ -0,0 +1,198 @@ +#ifdef CPU_CPP + +#include "irq.cpp" +#include "joypad.cpp" + +unsigned CPU::dma_counter() { + return (status.dma_counter + hcounter()) & 7; +} + +void CPU::add_clocks(unsigned clocks) { + status.irq_lock = false; + unsigned ticks = clocks >> 1; + while(ticks--) { + tick(); + if(hcounter() & 2) poll_interrupts(); + } + + step(clocks); + + status.auto_joypad_clock += clocks; + if(status.auto_joypad_clock >= 256) { + status.auto_joypad_clock -= 256; + step_auto_joypad_poll(); + } + + if(status.dram_refreshed == false && hcounter() >= status.dram_refresh_position) { + status.dram_refreshed = true; + add_clocks(40); + } +} + +//called by ppu.tick() when Hcounter=0 +void CPU::scanline() { + status.dma_counter = (status.dma_counter + status.line_clocks) & 7; + status.line_clocks = lineclocks(); + + //forcefully sync S-CPU to other processors, in case chips are not communicating + synchronize_ppu(); + synchronize_smp(); + synchronize_coprocessors(); + system.scanline(); + + if(vcounter() == 0) { + //HDMA init triggers once every frame + status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter()); + status.hdma_init_triggered = false; + + status.auto_joypad_counter = 0; + } + + //DRAM refresh occurs once every scanline + if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter(); + status.dram_refreshed = false; + + //HDMA triggers once every visible scanline + if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) { + status.hdma_position = 1104; + status.hdma_triggered = false; + } +} + +void CPU::alu_edge() { + if(alu.mpyctr) { + alu.mpyctr--; + if(status.rddiv & 1) status.rdmpy += alu.shift; + status.rddiv >>= 1; + alu.shift <<= 1; + } + + if(alu.divctr) { + alu.divctr--; + status.rddiv <<= 1; + alu.shift >>= 1; + if(status.rdmpy >= alu.shift) { + status.rdmpy -= alu.shift; + status.rddiv |= 1; + } + } +} + +void CPU::dma_edge() { + //H/DMA pending && DMA inactive? + //.. Run one full CPU cycle + //.. HDMA pending && HDMA enabled ? DMA sync + HDMA run + //.. DMA pending && DMA enabled ? DMA sync + DMA run + //.... HDMA during DMA && HDMA enabled ? DMA sync + HDMA run + //.. Run one bus CPU cycle + //.. CPU sync + + if(status.dma_active == true) { + if(status.hdma_pending) { + status.hdma_pending = false; + if(hdma_enabled_channels()) { + if(!dma_enabled_channels()) { + dma_add_clocks(8 - dma_counter()); + } + status.hdma_mode == 0 ? hdma_init() : hdma_run(); + if(!dma_enabled_channels()) { + add_clocks(status.clock_count - (status.dma_clocks % status.clock_count)); + status.dma_active = false; + } + } + } + + if(status.dma_pending) { + status.dma_pending = false; + if(dma_enabled_channels()) { + dma_add_clocks(8 - dma_counter()); + dma_run(); + add_clocks(status.clock_count - (status.dma_clocks % status.clock_count)); + status.dma_active = false; + } + } + } + + if(status.hdma_init_triggered == false && hcounter() >= status.hdma_init_position) { + status.hdma_init_triggered = true; + hdma_init_reset(); + if(hdma_enabled_channels()) { + status.hdma_pending = true; + status.hdma_mode = 0; + } + } + + if(status.hdma_triggered == false && hcounter() >= status.hdma_position) { + status.hdma_triggered = true; + if(hdma_active_channels()) { + status.hdma_pending = true; + status.hdma_mode = 1; + } + } + + if(status.dma_active == false) { + if(status.dma_pending || status.hdma_pending) { + status.dma_clocks = 0; + status.dma_active = true; + } + } +} + +//used to test for NMI/IRQ, which can trigger on the edge of every opcode. +//test one cycle early to simulate two-stage pipeline of x816 CPU. +// +//status.irq_lock is used to simulate hardware delay before interrupts can +//trigger during certain events (immediately after DMA, writes to $4200, etc) +void CPU::last_cycle() { + if(status.irq_lock == false) { + status.nmi_pending |= nmi_test(); + status.irq_pending |= irq_test(); + status.interrupt_pending = (status.nmi_pending || status.irq_pending); + } +} + +void CPU::timing_power() { +} + +void CPU::timing_reset() { + status.clock_count = 0; + status.line_clocks = lineclocks(); + + status.irq_lock = false; + status.dram_refresh_position = (cpu_version == 1 ? 530 : 538); + status.dram_refreshed = false; + + status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter()); + status.hdma_init_triggered = false; + + status.hdma_position = 1104; + status.hdma_triggered = false; + + status.nmi_valid = false; + status.nmi_line = false; + status.nmi_transition = false; + status.nmi_pending = false; + status.nmi_hold = false; + + status.irq_valid = false; + status.irq_line = false; + status.irq_transition = false; + status.irq_pending = false; + status.irq_hold = false; + + status.reset_pending = true; + status.interrupt_pending = true; + + status.dma_active = false; + status.dma_counter = 0; + status.dma_clocks = 0; + status.dma_pending = false; + status.hdma_pending = false; + status.hdma_mode = 0; + + status.auto_joypad_active = false; + status.auto_joypad_counter = 0; + status.auto_joypad_clock = 0; +} + +#endif diff --git a/snes/cpu/timing/timing.hpp b/snes/cpu/timing/timing.hpp new file mode 100755 index 00000000..6c225dab --- /dev/null +++ b/snes/cpu/timing/timing.hpp @@ -0,0 +1,24 @@ +//timing.cpp +unsigned dma_counter(); + +void add_clocks(unsigned clocks); +void scanline(); + +alwaysinline void alu_edge(); +alwaysinline void dma_edge(); +alwaysinline void last_cycle(); + +void timing_power(); +void timing_reset(); + +//irq.cpp +alwaysinline void poll_interrupts(); +void nmitimen_update(uint8 data); +bool rdnmi(); +bool timeup(); + +alwaysinline bool nmi_test(); +alwaysinline bool irq_test(); + +//joypad.cpp +void step_auto_joypad_poll(); diff --git a/snes/debugger/debugger.cpp b/snes/debugger/debugger.cpp new file mode 100755 index 00000000..b1312339 --- /dev/null +++ b/snes/debugger/debugger.cpp @@ -0,0 +1,108 @@ +#ifdef SYSTEM_CPP + +Debugger debugger; + +void Debugger::breakpoint_test(Debugger::Breakpoint::Source source, Debugger::Breakpoint::Mode mode, unsigned addr, uint8 data) { + for(unsigned i = 0; i < Breakpoints; i++) { + if(breakpoint[i].enabled == false) continue; + + bool source_wram = ((breakpoint[i].addr & 0x40e000) == 0x000000) || ((breakpoint[i].addr & 0xffe000) == 0x7e0000); + bool offset_wram = ((addr & 0x40e000) == 0x000000) || ((addr & 0xffe000) == 0x7e0000); + + if(source == Debugger::Breakpoint::Source::CPUBus && source_wram && offset_wram) { + //shadow S-CPU WRAM addresses ($00-3f|80-bf:0000-1fff mirrors $7e:0000-1fff) + if((breakpoint[i].addr & 0x1fff) != (addr & 0x1fff)) continue; + } else { + if(breakpoint[i].addr != addr) continue; + } + + if(breakpoint[i].data != -1 && breakpoint[i].data != data) continue; + if(breakpoint[i].source != source) continue; + if(breakpoint[i].mode != mode) continue; + + breakpoint[i].counter++; + breakpoint_hit = i; + break_event = BreakEvent::BreakpointHit; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + break; + } +} + +uint8 Debugger::read(Debugger::MemorySource source, unsigned addr) { + switch(source) { + case MemorySource::CPUBus: { + //do not read from memory-mapped registers that could affect program behavior + if(((addr - 0x2000) & 0x40c000) == 0x000000) break; //$00-3f:2000-5fff MMIO + return bus.read(addr & 0xffffff); + } break; + + case MemorySource::APUBus: { + if((addr & 0xffc0) == 0xffc0) return smp.iplrom[addr & 0x3f]; + return smp.apuram[addr & 0xffff]; + } break; + + case MemorySource::APURAM: { + return smp.apuram[addr & 0xffff]; + } break; + + case MemorySource::VRAM: { + return ppu.vram[addr & 0xffff]; + } break; + + case MemorySource::OAM: { + if(addr & 0x0200) return ppu.oam[0x0200 + (addr & 0x1f)]; + return ppu.oam[addr & 0x01ff]; + } break; + + case MemorySource::CGRAM: { + return ppu.cgram[addr & 0x01ff]; + } break; + } + + return 0x00; +} + +void Debugger::write(Debugger::MemorySource source, unsigned addr, uint8 data) { + switch(source) { + case MemorySource::CPUBus: { + //do not write to memory-mapped registers that could affect program behavior + if(((addr - 0x2000) & 0x40c000) == 0x000000) break; //$00-3f:2000-5fff MMIO + cartridge.rom.write_protect(false); + bus.write(addr & 0xffffff, data); + cartridge.rom.write_protect(true); + } break; + + case MemorySource::APURAM: { + smp.apuram[addr & 0xffff] = data; + } break; + + case MemorySource::VRAM: { + ppu.vram[addr & 0xffff] = data; + } break; + + case MemorySource::OAM: { + if(addr & 0x0200) ppu.oam[0x0200 + (addr & 0x1f)] = data; + else ppu.oam[addr & 0x01ff] = data; + } break; + + case MemorySource::CGRAM: { + ppu.cgram[addr & 0x01ff] = data; + } break; + } +} + +Debugger::Debugger() { + break_event = BreakEvent::None; + + for(unsigned n = 0; n < Breakpoints; n++) { + breakpoint[n].enabled = false; + breakpoint[n].addr = 0; + breakpoint[n].data = -1; + breakpoint[n].mode = Breakpoint::Mode::Exec; + breakpoint[n].source = Breakpoint::Source::CPUBus; + breakpoint[n].counter = 0; + } + breakpoint_hit = 0; +} + +#endif diff --git a/snes/debugger/debugger.hpp b/snes/debugger/debugger.hpp new file mode 100755 index 00000000..8a4c1ba2 --- /dev/null +++ b/snes/debugger/debugger.hpp @@ -0,0 +1,28 @@ +struct Debugger { + enum class BreakEvent : unsigned { + None, + BreakpointHit, + CPUStep, + SMPStep, + } break_event; + + enum { Breakpoints = 8 }; + struct Breakpoint { + bool enabled; + unsigned addr; + signed data; //-1 = unused + enum class Mode : unsigned { Exec, Read, Write } mode; + enum class Source : unsigned { CPUBus, APURAM, VRAM, OAM, CGRAM } source; + unsigned counter; //number of times breakpoint has been hit since being set + } breakpoint[Breakpoints]; + unsigned breakpoint_hit; + void breakpoint_test(Breakpoint::Source source, Breakpoint::Mode mode, unsigned addr, uint8 data); + + enum class MemorySource : unsigned { CPUBus, APUBus, APURAM, VRAM, OAM, CGRAM }; + uint8 read(MemorySource, unsigned addr); + void write(MemorySource, unsigned addr, uint8 data); + + Debugger(); +}; + +extern Debugger debugger; diff --git a/snes/dsp/brr.cpp b/snes/dsp/brr.cpp new file mode 100755 index 00000000..8552d7aa --- /dev/null +++ b/snes/dsp/brr.cpp @@ -0,0 +1,62 @@ +#ifdef DSP_CPP + +void DSP::brr_decode(voice_t &v) { + //state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle + int nybbles = (state.t_brr_byte << 8) + smp.apuram[(uint16)(v.brr_addr + v.brr_offset + 1)]; + + const int filter = (state.t_brr_header >> 2) & 3; + const int scale = (state.t_brr_header >> 4); + + //decode four samples + for(unsigned i = 0; i < 4; i++) { + //bits 12-15 = current nybble; sign extend, then shift right to 4-bit precision + //result: s = 4-bit sign-extended sample value + int s = (int16)nybbles >> 12; + nybbles <<= 4; //slide nybble so that on next loop iteration, bits 12-15 = current nybble + + if(scale <= 12) { + s <<= scale; + s >>= 1; + } else { + s &= ~0x7ff; + } + + //apply IIR filter (2 is the most commonly used) + const int p1 = v.buffer[v.buf_pos - 1]; + const int p2 = v.buffer[v.buf_pos - 2] >> 1; + + switch(filter) { + case 0: break; //no filter + + case 1: { + //s += p1 * 0.46875 + s += p1 >> 1; + s += (-p1) >> 5; + } break; + + case 2: { + //s += p1 * 0.953125 - p2 * 0.46875 + s += p1; + s -= p2; + s += p2 >> 4; + s += (p1 * -3) >> 6; + } break; + + case 3: { + //s += p1 * 0.8984375 - p2 * 0.40625 + s += p1; + s -= p2; + s += (p1 * -13) >> 7; + s += (p2 * 3) >> 4; + } break; + } + + //adjust and write sample + s = sclamp<16>(s); + s = (int16)(s << 1); + v.buffer.write(v.buf_pos++, s); + if(v.buf_pos >= brr_buf_size) v.buf_pos = 0; + } +} + +#endif diff --git a/snes/dsp/counter.cpp b/snes/dsp/counter.cpp new file mode 100755 index 00000000..f65fdd26 --- /dev/null +++ b/snes/dsp/counter.cpp @@ -0,0 +1,52 @@ +#ifdef DSP_CPP + +//counter_rate = number of samples per counter event +//all rates are evenly divisible by counter_range (0x7800, 30720, or 2048 * 5 * 3) +//note that rate[0] is a special case, which never triggers + +const uint16 DSP::counter_rate[32] = { + 0, 2048, 1536, + 1280, 1024, 768, + 640, 512, 384, + 320, 256, 192, + 160, 128, 96, + 80, 64, 48, + 40, 32, 24, + 20, 16, 12, + 10, 8, 6, + 5, 4, 3, + 2, + 1, +}; + +//counter_offset = counter offset from zero +//counters do not appear to be aligned at zero for all rates + +const uint16 DSP::counter_offset[32] = { + 0, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 536, 0, 1040, + 0, + 0, +}; + +inline void DSP::counter_tick() { + state.counter--; + if(state.counter < 0) state.counter = counter_range - 1; +} + +//return true if counter event should trigger + +inline bool DSP::counter_poll(unsigned rate) { + if(rate == 0) return false; + return (((unsigned)state.counter + counter_offset[rate]) % counter_rate[rate]) == 0; +} + +#endif diff --git a/snes/dsp/debugger/debugger.cpp b/snes/dsp/debugger/debugger.cpp new file mode 100755 index 00000000..b7a5e3b5 --- /dev/null +++ b/snes/dsp/debugger/debugger.cpp @@ -0,0 +1,53 @@ +#ifdef DSP_CPP + +bool DSPDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + item("Main Volume - Left", (unsigned)state.regs[0x0c]); + item("Main Volume - Right", (unsigned)state.regs[0x1c]); + item("Echo Volume - Left", (unsigned)state.regs[0x2c]); + item("Echo Volume - Right", (unsigned)state.regs[0x3c]); + item("Key On", string("0x", hex<2>(state.regs[0x4c]))); + item("Key Off", string("0x", hex<2>(state.regs[0x5c]))); + item("Flag - Reset", (bool)(state.regs[0x6c] & 0x80)); + item("Flag - Mute", (bool)(state.regs[0x6c] & 0x40)); + item("Flag - Echo Disable", (bool)(state.regs[0x6c] & 0x20)); + item("Flag - Noise Clock", (unsigned)state.regs[0x6c] & 0x1f); + item("Source End Block", (unsigned)state.regs[0x7c]); + item("Echo Feedback", (unsigned)state.regs[0x0d]); + item("Pitch Modulation Enable", string("0x", hex<2>(state.regs[0x2d]))); + item("Noise Enable", string("0x", hex<2>(state.regs[0x3d]))); + item("Echo Enable", string("0x", hex<2>(state.regs[0x4d]))); + item("Source Directory", (unsigned)state.regs[0x5d]); + item("Echo Start Address", (unsigned)state.regs[0x6d]); + item("Echo Directory", (unsigned)state.regs[0x7d]); + + for(unsigned i = 0; i < 8; i++) { + item(string("Coefficient ", i), string("0x", hex<2>(state.regs[(i << 4) + 0x0f]))); + } + + for(unsigned i = 0; i < 8; i++) { + item(string("Voice ", i), ""); + item("Volume - Left", (unsigned)state.regs[(i << 4) + 0x00]); + item("Volume - Right", (unsigned)state.regs[(i << 4) + 0x01]); + item("Pitch Height", string("0x", hex<4>(state.regs[(i << 4) + 0x02] + (state.regs[(i << 4) + 0x03] << 8)))); + item("Source Number", (unsigned)state.regs[(i << 4) + 0x04]); + item("ADSR1", (unsigned)state.regs[(i << 4) + 0x05]); + item("ADSR2", (unsigned)state.regs[(i << 4) + 0x06]); + item("GAIN", (unsigned)state.regs[(i << 4) + 0x07]); + item("ENVX", (unsigned)state.regs[(i << 4) + 0x08]); + item("OUTX", (unsigned)state.regs[(i << 4) + 0x09]); + } + + #undef item + return false; +} + +#endif diff --git a/snes/dsp/debugger/debugger.hpp b/snes/dsp/debugger/debugger.hpp new file mode 100755 index 00000000..3339ea3d --- /dev/null +++ b/snes/dsp/debugger/debugger.hpp @@ -0,0 +1,4 @@ +class DSPDebugger : public DSP, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); +}; diff --git a/snes/dsp/dsp.cpp b/snes/dsp/dsp.cpp new file mode 100755 index 00000000..4811269b --- /dev/null +++ b/snes/dsp/dsp.cpp @@ -0,0 +1,308 @@ +#include + +#define DSP_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + DSPDebugger dsp; +#else + DSP dsp; +#endif + +#include "serialization.cpp" + +#define REG(n) state.regs[r_##n] +#define VREG(n) state.regs[v.vidx + v_##n] + +#include "gaussian.cpp" +#include "counter.cpp" +#include "envelope.cpp" +#include "brr.cpp" +#include "misc.cpp" +#include "voice.cpp" +#include "echo.cpp" + +/* timing */ + +void DSP::step(unsigned clocks) { + clock += clocks; +} + +void DSP::synchronize_smp() { + if(SMP::Threaded == true) { + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(smp.thread); + } else { + while(clock >= 0) smp.enter(); + } +} + +void DSP::Enter() { dsp.enter(); } + +void DSP::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + voice_5(voice[0]); + voice_2(voice[1]); + tick(); + + voice_6(voice[0]); + voice_3(voice[1]); + tick(); + + voice_7(voice[0]); + voice_4(voice[1]); + voice_1(voice[3]); + tick(); + + voice_8(voice[0]); + voice_5(voice[1]); + voice_2(voice[2]); + tick(); + + voice_9(voice[0]); + voice_6(voice[1]); + voice_3(voice[2]); + tick(); + + voice_7(voice[1]); + voice_4(voice[2]); + voice_1(voice[4]); + tick(); + + voice_8(voice[1]); + voice_5(voice[2]); + voice_2(voice[3]); + tick(); + + voice_9(voice[1]); + voice_6(voice[2]); + voice_3(voice[3]); + tick(); + + voice_7(voice[2]); + voice_4(voice[3]); + voice_1(voice[5]); + tick(); + + voice_8(voice[2]); + voice_5(voice[3]); + voice_2(voice[4]); + tick(); + + voice_9(voice[2]); + voice_6(voice[3]); + voice_3(voice[4]); + tick(); + + voice_7(voice[3]); + voice_4(voice[4]); + voice_1(voice[6]); + tick(); + + voice_8(voice[3]); + voice_5(voice[4]); + voice_2(voice[5]); + tick(); + + voice_9(voice[3]); + voice_6(voice[4]); + voice_3(voice[5]); + tick(); + + voice_7(voice[4]); + voice_4(voice[5]); + voice_1(voice[7]); + tick(); + + voice_8(voice[4]); + voice_5(voice[5]); + voice_2(voice[6]); + tick(); + + voice_9(voice[4]); + voice_6(voice[5]); + voice_3(voice[6]); + tick(); + + voice_1(voice[0]); + voice_7(voice[5]); + voice_4(voice[6]); + tick(); + + voice_8(voice[5]); + voice_5(voice[6]); + voice_2(voice[7]); + tick(); + + voice_9(voice[5]); + voice_6(voice[6]); + voice_3(voice[7]); + tick(); + + voice_1(voice[1]); + voice_7(voice[6]); + voice_4(voice[7]); + tick(); + + voice_8(voice[6]); + voice_5(voice[7]); + voice_2(voice[0]); + tick(); + + voice_3a(voice[0]); + voice_9(voice[6]); + voice_6(voice[7]); + echo_22(); + tick(); + + voice_7(voice[7]); + echo_23(); + tick(); + + voice_8(voice[7]); + echo_24(); + tick(); + + voice_3b(voice[0]); + voice_9(voice[7]); + echo_25(); + tick(); + + echo_26(); + tick(); + + misc_27(); + echo_27(); + tick(); + + misc_28(); + echo_28(); + tick(); + + misc_29(); + echo_29(); + tick(); + + misc_30(); + voice_3c(voice[0]); + echo_30(); + tick(); + + voice_4(voice[0]); + voice_1(voice[2]); + tick(); + } +} + +void DSP::tick() { + step(3 * 8); + synchronize_smp(); +} + +/* register interface for S-SMP $00f2,$00f3 */ + +uint8 DSP::read(uint8 addr) { + return state.regs[addr]; +} + +void DSP::write(uint8 addr, uint8 data) { + state.regs[addr] = data; + + if((addr & 0x0f) == v_envx) { + state.envx_buf = data; + } else if((addr & 0x0f) == v_outx) { + state.outx_buf = data; + } else if(addr == r_kon) { + state.new_kon = data; + } else if(addr == r_endx) { + //always cleared, regardless of data written + state.endx_buf = 0; + state.regs[r_endx] = 0; + } +} + +/* initialization */ + +void DSP::power() { + memset(&state.regs, 0, sizeof state.regs); + state.echo_hist_pos = 0; + state.every_other_sample = false; + state.kon = 0; + state.noise = 0; + state.counter = 0; + state.echo_offset = 0; + state.echo_length = 0; + state.new_kon = 0; + state.endx_buf = 0; + state.envx_buf = 0; + state.outx_buf = 0; + state.t_pmon = 0; + state.t_non = 0; + state.t_eon = 0; + state.t_dir = 0; + state.t_koff = 0; + state.t_brr_next_addr = 0; + state.t_adsr0 = 0; + state.t_brr_header = 0; + state.t_brr_byte = 0; + state.t_srcn = 0; + state.t_esa = 0; + state.t_echo_disabled = 0; + state.t_dir_addr = 0; + state.t_pitch = 0; + state.t_output = 0; + state.t_looped = 0; + state.t_echo_ptr = 0; + state.t_main_out[0] = state.t_main_out[1] = 0; + state.t_echo_out[0] = state.t_echo_out[1] = 0; + state.t_echo_in[0] = state.t_echo_in[1] = 0; + + for(unsigned i = 0; i < 8; i++) { + voice[i].buf_pos = 0; + voice[i].interp_pos = 0; + voice[i].brr_addr = 0; + voice[i].brr_offset = 1; + voice[i].vbit = 1 << i; + voice[i].vidx = i * 0x10; + voice[i].kon_delay = 0; + voice[i].env_mode = env_release; + voice[i].env = 0; + voice[i].t_envx_out = 0; + voice[i].hidden_env = 0; + } + + reset(); +} + +void DSP::reset() { + create(Enter, system.apu_frequency()); + + REG(flg) = 0xe0; + + state.noise = 0x4000; + state.echo_hist_pos = 0; + state.every_other_sample = 1; + state.echo_offset = 0; + state.counter = 0; +} + +DSP::DSP() { + static_assert(sizeof(int) >= 32 / 8, "int >= 32-bits"); + static_assert((int8)0x80 == -0x80, "8-bit sign extension"); + static_assert((int16)0x8000 == -0x8000, "16-bit sign extension"); + static_assert((uint16)0xffff0000 == 0, "16-bit unsigned clip"); + static_assert((-1 >> 1) == -1, "arithmetic shift right"); + + //-0x8000 <= n <= +0x7fff + assert(sclamp<16>(+0x8000) == +0x7fff); + assert(sclamp<16>(-0x8001) == -0x8000); +} + +DSP::~DSP() { +} + +} diff --git a/snes/dsp/dsp.hpp b/snes/dsp/dsp.hpp new file mode 100755 index 00000000..10fcc9cb --- /dev/null +++ b/snes/dsp/dsp.hpp @@ -0,0 +1,179 @@ +struct DSP : public Processor { + enum : bool { Threaded = true }; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_smp(); + + uint8 read(uint8 addr); + void write(uint8 addr, uint8 data); + + void enter(); + void power(); + void reset(); + + void serialize(serializer&); + DSP(); + ~DSP(); + +private: + //global registers + enum global_reg_t { + r_mvoll = 0x0c, r_mvolr = 0x1c, + r_evoll = 0x2c, r_evolr = 0x3c, + r_kon = 0x4c, r_koff = 0x5c, + r_flg = 0x6c, r_endx = 0x7c, + r_efb = 0x0d, r_pmon = 0x2d, + r_non = 0x3d, r_eon = 0x4d, + r_dir = 0x5d, r_esa = 0x6d, + r_edl = 0x7d, r_fir = 0x0f, //8 coefficients at 0x0f, 0x1f, ... 0x7f + }; + + //voice registers + enum voice_reg_t { + v_voll = 0x00, v_volr = 0x01, + v_pitchl = 0x02, v_pitchh = 0x03, + v_srcn = 0x04, v_adsr0 = 0x05, + v_adsr1 = 0x06, v_gain = 0x07, + v_envx = 0x08, v_outx = 0x09, + }; + + //internal envelope modes + enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; + + //internal constants + enum { echo_hist_size = 8 }; + enum { brr_buf_size = 12 }; + enum { brr_block_size = 9 }; + + //global state + struct state_t { + uint8 regs[128]; + + modulo_array echo_hist[2]; //echo history keeps most recent 8 samples + int echo_hist_pos; + + bool every_other_sample; //toggles every sample + int kon; //KON value when last checked + int noise; + int counter; + int echo_offset; //offset from ESA in echo buffer + int echo_length; //number of bytes that echo_offset will stop at + + //hidden registers also written to when main register is written to + int new_kon; + int endx_buf; + int envx_buf; + int outx_buf; + + //temporary state between clocks + + //read once per sample + int t_pmon; + int t_non; + int t_eon; + int t_dir; + int t_koff; + + //read a few clocks ahead before used + int t_brr_next_addr; + int t_adsr0; + int t_brr_header; + int t_brr_byte; + int t_srcn; + int t_esa; + int t_echo_disabled; + + //internal state that is recalculated every sample + int t_dir_addr; + int t_pitch; + int t_output; + int t_looped; + int t_echo_ptr; + + //left/right sums + int t_main_out[2]; + int t_echo_out[2]; + int t_echo_in [2]; + } state; + + //voice state + struct voice_t { + modulo_array buffer; //decoded samples + int buf_pos; //place in buffer where next samples will be decoded + int interp_pos; //relative fractional position in sample (0x1000 = 1.0) + int brr_addr; //address of current BRR block + int brr_offset; //current decoding offset in BRR block + int vbit; //bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc + int vidx; //voice channel register index: 0x00 for voice 0, 0x10 for voice 1, etc + int kon_delay; //KON delay/current setup phase + int env_mode; + int env; //current envelope level + int t_envx_out; + int hidden_env; //used by GAIN mode 7, very obscure quirk + } voice[8]; + + //gaussian + static const int16 gaussian_table[512]; + int gaussian_interpolate(const voice_t &v); + + //counter + enum { counter_range = 2048 * 5 * 3 }; //30720 (0x7800) + static const uint16 counter_rate[32]; + static const uint16 counter_offset[32]; + void counter_tick(); + bool counter_poll(unsigned rate); + + //envelope + void envelope_run(voice_t &v); + + //brr + void brr_decode(voice_t &v); + + //misc + void misc_27(); + void misc_28(); + void misc_29(); + void misc_30(); + + //voice + void voice_output(voice_t &v, bool channel); + void voice_1 (voice_t &v); + void voice_2 (voice_t &v); + void voice_3 (voice_t &v); + void voice_3a(voice_t &v); + void voice_3b(voice_t &v); + void voice_3c(voice_t &v); + void voice_4 (voice_t &v); + void voice_5 (voice_t &v); + void voice_6 (voice_t &v); + void voice_7 (voice_t &v); + void voice_8 (voice_t &v); + void voice_9 (voice_t &v); + + //echo + int calc_fir(int i, bool channel); + int echo_output(bool channel); + void echo_read(bool channel); + void echo_write(bool channel); + void echo_22(); + void echo_23(); + void echo_24(); + void echo_25(); + void echo_26(); + void echo_27(); + void echo_28(); + void echo_29(); + void echo_30(); + + //dsp + static void Enter(); + void tick(); + + friend class DSPDebugger; +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern DSPDebugger dsp; +#else + extern DSP dsp; +#endif diff --git a/snes/dsp/echo.cpp b/snes/dsp/echo.cpp new file mode 100755 index 00000000..b80de85d --- /dev/null +++ b/snes/dsp/echo.cpp @@ -0,0 +1,135 @@ +#ifdef DSP_CPP + +int DSP::calc_fir(int i, bool channel) { + int s = state.echo_hist[channel][state.echo_hist_pos + i + 1]; + return (s * (int8)REG(fir + i * 0x10)) >> 6; +} + +int DSP::echo_output(bool channel) { + int output = (int16)((state.t_main_out[channel] * (int8)REG(mvoll + channel * 0x10)) >> 7) + + (int16)((state.t_echo_in [channel] * (int8)REG(evoll + channel * 0x10)) >> 7); + return sclamp<16>(output); +} + +void DSP::echo_read(bool channel) { + unsigned addr = state.t_echo_ptr + channel * 2; + uint8 lo = smp.apuram[(uint16)(addr + 0)]; + uint8 hi = smp.apuram[(uint16)(addr + 1)]; + int s = (int16)((hi << 8) + lo); + state.echo_hist[channel].write(state.echo_hist_pos, s >> 1); +} + +void DSP::echo_write(bool channel) { + if(!(state.t_echo_disabled & 0x20)) { + unsigned addr = state.t_echo_ptr + channel * 2; + int s = state.t_echo_out[channel]; + smp.apuram[(uint16)(addr + 0)] = s; + smp.apuram[(uint16)(addr + 1)] = s >> 8; + } + + state.t_echo_out[channel] = 0; +} + +void DSP::echo_22() { + //history + state.echo_hist_pos++; + if(state.echo_hist_pos >= echo_hist_size) state.echo_hist_pos = 0; + + state.t_echo_ptr = (uint16)((state.t_esa << 8) + state.echo_offset); + echo_read(0); + + //FIR + int l = calc_fir(0, 0); + int r = calc_fir(0, 1); + + state.t_echo_in[0] = l; + state.t_echo_in[1] = r; +} + +void DSP::echo_23() { + int l = calc_fir(1, 0) + calc_fir(2, 0); + int r = calc_fir(1, 1) + calc_fir(2, 1); + + state.t_echo_in[0] += l; + state.t_echo_in[1] += r; + + echo_read(1); +} + +void DSP::echo_24() { + int l = calc_fir(3, 0) + calc_fir(4, 0) + calc_fir(5, 0); + int r = calc_fir(3, 1) + calc_fir(4, 1) + calc_fir(5, 1); + + state.t_echo_in[0] += l; + state.t_echo_in[1] += r; +} + +void DSP::echo_25() { + int l = state.t_echo_in[0] + calc_fir(6, 0); + int r = state.t_echo_in[1] + calc_fir(6, 1); + + l = (int16)l; + r = (int16)r; + + l += (int16)calc_fir(7, 0); + r += (int16)calc_fir(7, 1); + + state.t_echo_in[0] = sclamp<16>(l) & ~1; + state.t_echo_in[1] = sclamp<16>(r) & ~1; +} + +void DSP::echo_26() { + //left output volumes + //(save sample for next clock so we can output both together) + state.t_main_out[0] = echo_output(0); + + //echo feedback + int l = state.t_echo_out[0] + (int16)((state.t_echo_in[0] * (int8)REG(efb)) >> 7); + int r = state.t_echo_out[1] + (int16)((state.t_echo_in[1] * (int8)REG(efb)) >> 7); + + state.t_echo_out[0] = sclamp<16>(l) & ~1; + state.t_echo_out[1] = sclamp<16>(r) & ~1; +} + +void DSP::echo_27() { + //output + int outl = state.t_main_out[0]; + int outr = echo_output(1); + state.t_main_out[0] = 0; + state.t_main_out[1] = 0; + + //TODO: global muting isn't this simple + //(turns DAC on and off or something, causing small ~37-sample pulse when first muted) + if(REG(flg) & 0x40) { + outl = 0; + outr = 0; + } + + //output sample to DAC + audio.sample(outl, outr); +} + +void DSP::echo_28() { + state.t_echo_disabled = REG(flg); +} + +void DSP::echo_29() { + state.t_esa = REG(esa); + + if(!state.echo_offset) state.echo_length = (REG(edl) & 0x0f) << 11; + + state.echo_offset += 4; + if(state.echo_offset >= state.echo_length) state.echo_offset = 0; + + //write left echo + echo_write(0); + + state.t_echo_disabled = REG(flg); +} + +void DSP::echo_30() { + //write right echo + echo_write(1); +} + +#endif diff --git a/snes/dsp/envelope.cpp b/snes/dsp/envelope.cpp new file mode 100755 index 00000000..9ae0d3e0 --- /dev/null +++ b/snes/dsp/envelope.cpp @@ -0,0 +1,62 @@ +#ifdef DSP_CPP + +void DSP::envelope_run(voice_t &v) { + int env = v.env; + + if(v.env_mode == env_release) { //60% + env -= 0x8; + if(env < 0) env = 0; + v.env = env; + return; + } + + int rate; + int env_data = VREG(adsr1); + if(state.t_adsr0 & 0x80) { //99% ADSR + if(v.env_mode >= env_decay) { //99% + env--; + env -= env >> 8; + rate = env_data & 0x1f; + if(v.env_mode == env_decay) { //1% + rate = ((state.t_adsr0 >> 3) & 0x0e) + 0x10; + } + } else { //env_attack + rate = ((state.t_adsr0 & 0x0f) << 1) + 1; + env += rate < 31 ? 0x20 : 0x400; + } + } else { //GAIN + env_data = VREG(gain); + int mode = env_data >> 5; + if(mode < 4) { //direct + env = env_data << 4; + rate = 31; + } else { + rate = env_data & 0x1f; + if(mode == 4) { //4: linear decrease + env -= 0x20; + } else if(mode < 6) { //5: exponential decrease + env--; + env -= env >> 8; + } else { //6, 7: linear increase + env += 0x20; + if(mode > 6 && (unsigned)v.hidden_env >= 0x600) { + env += 0x8 - 0x20; //7: two-slope linear increase + } + } + } + } + + //sustain level + if((env >> 8) == (env_data >> 5) && v.env_mode == env_decay) v.env_mode = env_sustain; + v.hidden_env = env; + + //unsigned cast because linear decrease underflowing also triggers this + if((unsigned)env > 0x7ff) { + env = (env < 0 ? 0 : 0x7ff); + if(v.env_mode == env_attack) v.env_mode = env_decay; + } + + if(counter_poll(rate) == true) v.env = env; +} + +#endif diff --git a/snes/dsp/gaussian.cpp b/snes/dsp/gaussian.cpp new file mode 100755 index 00000000..80aed8ad --- /dev/null +++ b/snes/dsp/gaussian.cpp @@ -0,0 +1,54 @@ +#ifdef DSP_CPP + +const int16 DSP::gaussian_table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997, 1001, 1005, 1010, 1014, 1019, 1023, 1027, 1032, 1036, + 1040, 1045, 1049, 1053, 1057, 1061, 1066, 1070, 1074, 1078, 1082, 1086, 1090, 1094, 1098, 1102, + 1106, 1109, 1113, 1117, 1121, 1125, 1128, 1132, 1136, 1139, 1143, 1146, 1150, 1153, 1157, 1160, + 1164, 1167, 1170, 1174, 1177, 1180, 1183, 1186, 1190, 1193, 1196, 1199, 1202, 1205, 1207, 1210, + 1213, 1216, 1219, 1221, 1224, 1227, 1229, 1232, 1234, 1237, 1239, 1241, 1244, 1246, 1248, 1251, + 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280, + 1282, 1283, 1284, 1286, 1287, 1288, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1297, 1298, + 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305, +}; + +int DSP::gaussian_interpolate(const voice_t &v) { + //make pointers into gaussian table based on fractional position between samples + int offset = (v.interp_pos >> 4) & 0xff; + const int16 *fwd = gaussian_table + 255 - offset; + const int16 *rev = gaussian_table + offset; //mirror left half of gaussian table + + offset = v.buf_pos + (v.interp_pos >> 12); + int output; + output = (fwd[ 0] * v.buffer[offset + 0]) >> 11; + output += (fwd[256] * v.buffer[offset + 1]) >> 11; + output += (rev[256] * v.buffer[offset + 2]) >> 11; + output = (int16)output; + output += (rev[ 0] * v.buffer[offset + 3]) >> 11; + return sclamp<16>(output) & ~1; +} + +#endif diff --git a/snes/dsp/misc.cpp b/snes/dsp/misc.cpp new file mode 100755 index 00000000..244fc51f --- /dev/null +++ b/snes/dsp/misc.cpp @@ -0,0 +1,35 @@ +#ifdef DSP_CPP + +void DSP::misc_27() { + state.t_pmon = REG(pmon) & ~1; //voice 0 doesn't support PMON +} + +void DSP::misc_28() { + state.t_non = REG(non); + state.t_eon = REG(eon); + state.t_dir = REG(dir); +} + +void DSP::misc_29() { + state.every_other_sample ^= 1; + if(state.every_other_sample) { + state.new_kon &= ~state.kon; //clears KON 63 clocks after it was last read + } +} + +void DSP::misc_30() { + if(state.every_other_sample) { + state.kon = state.new_kon; + state.t_koff = REG(koff); + } + + counter_tick(); + + //noise + if(counter_poll(REG(flg) & 0x1f) == true) { + int feedback = (state.noise << 13) ^ (state.noise << 14); + state.noise = (feedback & 0x4000) ^ (state.noise >> 1); + } +} + +#endif diff --git a/snes/dsp/serialization.cpp b/snes/dsp/serialization.cpp new file mode 100755 index 00000000..0595c11e --- /dev/null +++ b/snes/dsp/serialization.cpp @@ -0,0 +1,66 @@ +#ifdef DSP_CPP + +void DSP::serialize(serializer &s) { + Processor::serialize(s); + + s.array(state.regs, 128); + state.echo_hist[0].serialize(s); + state.echo_hist[1].serialize(s); + s.integer(state.echo_hist_pos); + + s.integer(state.every_other_sample); + s.integer(state.kon); + s.integer(state.noise); + s.integer(state.counter); + s.integer(state.echo_offset); + s.integer(state.echo_length); + + s.integer(state.new_kon); + s.integer(state.endx_buf); + s.integer(state.envx_buf); + s.integer(state.outx_buf); + + s.integer(state.t_pmon); + s.integer(state.t_non); + s.integer(state.t_eon); + s.integer(state.t_dir); + s.integer(state.t_koff); + + s.integer(state.t_brr_next_addr); + s.integer(state.t_adsr0); + s.integer(state.t_brr_header); + s.integer(state.t_brr_byte); + s.integer(state.t_srcn); + s.integer(state.t_esa); + s.integer(state.t_echo_disabled); + + s.integer(state.t_dir_addr); + s.integer(state.t_pitch); + s.integer(state.t_output); + s.integer(state.t_looped); + s.integer(state.t_echo_ptr); + + s.integer(state.t_main_out[0]); + s.integer(state.t_main_out[1]); + s.integer(state.t_echo_out[0]); + s.integer(state.t_echo_out[1]); + s.integer(state.t_echo_in [0]); + s.integer(state.t_echo_in [1]); + + for(unsigned n = 0; n < 8; n++) { + voice[n].buffer.serialize(s); + s.integer(voice[n].buf_pos); + s.integer(voice[n].interp_pos); + s.integer(voice[n].brr_addr); + s.integer(voice[n].brr_offset); + s.integer(voice[n].vbit); + s.integer(voice[n].vidx); + s.integer(voice[n].kon_delay); + s.integer(voice[n].env_mode); + s.integer(voice[n].env); + s.integer(voice[n].t_envx_out); + s.integer(voice[n].hidden_env); + } +} + +#endif diff --git a/snes/dsp/voice.cpp b/snes/dsp/voice.cpp new file mode 100755 index 00000000..f4fcd8c0 --- /dev/null +++ b/snes/dsp/voice.cpp @@ -0,0 +1,174 @@ +#ifdef DSP_CPP + +inline void DSP::voice_output(voice_t &v, bool channel) { + //apply left/right volume + int amp = (state.t_output * (int8)VREG(voll + channel)) >> 7; + + //add to output total + state.t_main_out[channel] += amp; + state.t_main_out[channel] = sclamp<16>(state.t_main_out[channel]); + + //optionally add to echo total + if(state.t_eon & v.vbit) { + state.t_echo_out[channel] += amp; + state.t_echo_out[channel] = sclamp<16>(state.t_echo_out[channel]); + } +} + +void DSP::voice_1(voice_t &v) { + state.t_dir_addr = (state.t_dir << 8) + (state.t_srcn << 2); + state.t_srcn = VREG(srcn); +} + +void DSP::voice_2(voice_t &v) { + //read sample pointer (ignored if not needed) + uint16 addr = state.t_dir_addr; + if(!v.kon_delay) addr += 2; + uint8 lo = smp.apuram[(uint16)(addr + 0)]; + uint8 hi = smp.apuram[(uint16)(addr + 1)]; + state.t_brr_next_addr = ((hi << 8) + lo); + + state.t_adsr0 = VREG(adsr0); + + //read pitch, spread over two clocks + state.t_pitch = VREG(pitchl); +} + +void DSP::voice_3(voice_t &v) { + voice_3a(v); + voice_3b(v); + voice_3c(v); +} + +void DSP::voice_3a(voice_t &v) { + state.t_pitch += (VREG(pitchh) & 0x3f) << 8; +} + +void DSP::voice_3b(voice_t &v) { + state.t_brr_byte = smp.apuram[(uint16)(v.brr_addr + v.brr_offset)]; + state.t_brr_header = smp.apuram[(uint16)(v.brr_addr)]; +} + +void DSP::voice_3c(voice_t &v) { + //pitch modulation using previous voice's output + + if(state.t_pmon & v.vbit) { + state.t_pitch += ((state.t_output >> 5) * state.t_pitch) >> 10; + } + + if(v.kon_delay) { + //get ready to start BRR decoding on next sample + if(v.kon_delay == 5) { + v.brr_addr = state.t_brr_next_addr; + v.brr_offset = 1; + v.buf_pos = 0; + state.t_brr_header = 0; //header is ignored on this sample + } + + //envelope is never run during KON + v.env = 0; + v.hidden_env = 0; + + //disable BRR decoding until last three samples + v.interp_pos = 0; + v.kon_delay--; + if(v.kon_delay & 3) v.interp_pos = 0x4000; + + //pitch is never added during KON + state.t_pitch = 0; + } + + //gaussian interpolation + int output = gaussian_interpolate(v); + + //noise + if(state.t_non & v.vbit) { + output = (int16)(state.noise << 1); + } + + //apply envelope + state.t_output = ((output * v.env) >> 11) & ~1; + v.t_envx_out = v.env >> 4; + + //immediate silence due to end of sample or soft reset + if(REG(flg) & 0x80 || (state.t_brr_header & 3) == 1) { + v.env_mode = env_release; + v.env = 0; + } + + if(state.every_other_sample) { + //KOFF + if(state.t_koff & v.vbit) { + v.env_mode = env_release; + } + + //KON + if(state.kon & v.vbit) { + v.kon_delay = 5; + v.env_mode = env_attack; + } + } + + //run envelope for next sample + if(!v.kon_delay) envelope_run(v); +} + +void DSP::voice_4(voice_t &v) { + //decode BRR + state.t_looped = 0; + if(v.interp_pos >= 0x4000) { + brr_decode(v); + v.brr_offset += 2; + if(v.brr_offset >= 9) { + //start decoding next BRR block + v.brr_addr = (uint16)(v.brr_addr + 9); + if(state.t_brr_header & 1) { + v.brr_addr = state.t_brr_next_addr; + state.t_looped = v.vbit; + } + v.brr_offset = 1; + } + } + + //apply pitch + v.interp_pos = (v.interp_pos & 0x3fff) + state.t_pitch; + + //keep from getting too far ahead (when using pitch modulation) + if(v.interp_pos > 0x7fff) v.interp_pos = 0x7fff; + + //output left + voice_output(v, 0); +} + +void DSP::voice_5(voice_t &v) { + //output right + voice_output(v, 1); + + //ENDX, OUTX and ENVX won't update if you wrote to them 1-2 clocks earlier + state.endx_buf = REG(endx) | state.t_looped; + + //clear bit in ENDX if KON just began + if(v.kon_delay == 5) state.endx_buf &= ~v.vbit; +} + +void DSP::voice_6(voice_t &v) { + state.outx_buf = state.t_output >> 8; +} + +void DSP::voice_7(voice_t &v) { + //update ENDX + REG(endx) = (uint8)state.endx_buf; + state.envx_buf = v.t_envx_out; +} + +void DSP::voice_8(voice_t &v) { + //update OUTX + VREG(outx) = (uint8)state.outx_buf; +} + +void DSP::voice_9(voice_t &v) { + //update ENVX + VREG(envx) = (uint8)state.envx_buf; +} + +#endif diff --git a/snes/input/input.cpp b/snes/input/input.cpp new file mode 100755 index 00000000..90503106 --- /dev/null +++ b/snes/input/input.cpp @@ -0,0 +1,39 @@ +#ifdef SYSTEM_CPP + +Input input; + +void Input::connect(bool port, Input::Device id) { + Controller *&controller = (port == Controller::Port1 ? port1 : port2); + if(controller) { + delete controller; + controller = nullptr; + } + + 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; + } + + switch(port) { + case Controller::Port1: config.controller_port1 = id; break; + case Controller::Port2: config.controller_port2 = id; break; + } +} + +Input::Input() : port1(nullptr), port2(nullptr) { + connect(Controller::Port1, Input::Device::Joypad); + connect(Controller::Port2, Input::Device::Joypad); +} + +Input::~Input() { + if(port1) delete port1; + if(port2) delete port2; +} + +#endif diff --git a/snes/input/input.hpp b/snes/input/input.hpp new file mode 100755 index 00000000..13ef46e1 --- /dev/null +++ b/snes/input/input.hpp @@ -0,0 +1,39 @@ +struct Input { + enum class Device : unsigned { + None, + Joypad, + Multitap, + Mouse, + SuperScope, + Justifier, + Justifiers, + Serial, + }; + + enum class JoypadID : unsigned { + B = 0, Y = 1, Select = 2, Start = 3, + Up = 4, Down = 5, Left = 6, Right = 7, + A = 8, X = 9, L = 10, R = 11, + }; + + enum class MouseID : unsigned { + X = 0, Y = 1, Left = 2, Right = 3, + }; + + enum class SuperScopeID : unsigned { + X = 0, Y = 1, Trigger = 2, Cursor = 3, Turbo = 4, Pause = 5, + }; + + enum class JustifierID : unsigned { + X = 0, Y = 1, Trigger = 2, Start = 3, + }; + + Controller *port1; + Controller *port2; + + void connect(bool port, Input::Device id); + Input(); + ~Input(); +}; + +extern Input input; diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp new file mode 100755 index 00000000..a0e3a81b --- /dev/null +++ b/snes/interface/interface.cpp @@ -0,0 +1,21 @@ +#include + +namespace SNES { + +Interface *interface = nullptr; + +void Interface::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) { +} + +void Interface::audioSample(int16_t l_sample, int16_t r_sample) { +} + +int16_t Interface::inputPoll(bool port, Input::Device device, unsigned index, unsigned id) { + return 0; +} + +void Interface::message(const string &text) { + print(text, "\n"); +} + +} diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp new file mode 100755 index 00000000..f1a48c0f --- /dev/null +++ b/snes/interface/interface.hpp @@ -0,0 +1,10 @@ +struct Interface { + virtual void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan); + virtual void audioSample(int16_t lsample, int16_t rsample); + virtual int16_t inputPoll(bool port, Input::Device device, unsigned index, unsigned id); + + virtual string path(Cartridge::Slot slot, const string &hint) = 0; + virtual void message(const string &text); +}; + +extern Interface *interface; diff --git a/snes/memory/memory-inline.hpp b/snes/memory/memory-inline.hpp new file mode 100755 index 00000000..70503bea --- /dev/null +++ b/snes/memory/memory-inline.hpp @@ -0,0 +1,61 @@ +//Memory + +unsigned Memory::size() const { return 0; } + +//StaticRAM + +uint8* StaticRAM::data() { return data_; } +unsigned StaticRAM::size() const { return size_; } + +uint8 StaticRAM::read(unsigned addr) { return data_[addr]; } +void StaticRAM::write(unsigned addr, uint8 n) { data_[addr] = n; } +uint8& StaticRAM::operator[](unsigned addr) { return data_[addr]; } +const uint8& StaticRAM::operator[](unsigned addr) const { return data_[addr]; } + +StaticRAM::StaticRAM(unsigned n) : size_(n) { data_ = new uint8[size_]; } +StaticRAM::~StaticRAM() { delete[] data_; } + +//MappedRAM + +void MappedRAM::reset() { + if(data_) { + delete[] data_; + data_ = 0; + } + size_ = 0; + write_protect_ = false; +} + +void MappedRAM::map(uint8 *source, unsigned length) { + reset(); + data_ = source; + size_ = data_ ? length : 0; +} + +void MappedRAM::copy(const uint8 *data, unsigned size) { + if(!data_) { + size_ = (size & ~255) + ((bool)(size & 255) << 8); + data_ = new uint8[size_](); + } + memcpy(data_, data, min(size_, size)); +} + +void MappedRAM::write_protect(bool status) { write_protect_ = status; } +uint8* MappedRAM::data() { return data_; } +unsigned MappedRAM::size() const { return size_; } + +uint8 MappedRAM::read(unsigned addr) { return data_[addr]; } +void MappedRAM::write(unsigned addr, uint8 n) { if(!write_protect_) data_[addr] = n; } +const uint8& MappedRAM::operator[](unsigned addr) const { return data_[addr]; } +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]); +} + +void Bus::write(unsigned addr, uint8 data) { + return writer[lookup[addr]](target[addr], data); +} diff --git a/snes/memory/memory.cpp b/snes/memory/memory.cpp new file mode 100755 index 00000000..ede9cbd0 --- /dev/null +++ b/snes/memory/memory.cpp @@ -0,0 +1,79 @@ +#include + +#define MEMORY_CPP +namespace SNES { + +Bus bus; + +unsigned Bus::mirror(unsigned addr, unsigned size) { + unsigned base = 0; + if(size) { + unsigned mask = 1 << 23; + while(addr >= size) { + while(!(addr & mask)) mask >>= 1; + addr -= mask; + if(size > mask) { + size -= mask; + base += mask; + } + mask >>= 1; + } + base += addr; + } + return base; +} + +void Bus::map( + MapMode mode, + unsigned bank_lo, unsigned bank_hi, + unsigned addr_lo, unsigned addr_hi, + const function &rd, + const function &wr, + unsigned base, unsigned length +) { + assert(bank_lo <= bank_hi && bank_lo <= 0xff); + assert(addr_lo <= addr_hi && addr_lo <= 0xffff); + unsigned id = idcount++; + assert(id < 255); + reader[id] = rd; + writer[id] = wr; + + if(length == 0) length = (bank_hi - bank_lo + 1) * (addr_hi - addr_lo + 1); + + unsigned offset = 0; + for(unsigned bank = bank_lo; bank <= bank_hi; bank++) { + for(unsigned addr = addr_lo; addr <= addr_hi; addr++) { + unsigned destaddr = (bank << 16) | addr; + if(mode == MapMode::Linear) destaddr = mirror(base + offset++, length); + if(mode == MapMode::Shadow) destaddr = mirror(base + destaddr, length); + lookup[(bank << 16) | addr] = id; + target[(bank << 16) | addr] = destaddr; + } + } +} + +void Bus::map_reset() { + function reader = [](unsigned) { return cpu.regs.mdr; }; + function writer = [](unsigned, uint8) {}; + + idcount = 0; + map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, reader, writer); +} + +void Bus::map_xml() { + for(auto &m : cartridge.mapping) { + map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, m.read, m.write, m.offset, m.size); + } +} + +Bus::Bus() { + lookup = new uint8 [16 * 1024 * 1024]; + target = new uint32[16 * 1024 * 1024]; +} + +Bus::~Bus() { + delete[] lookup; + delete[] target; +} + +} diff --git a/snes/memory/memory.hpp b/snes/memory/memory.hpp new file mode 100755 index 00000000..634e0717 --- /dev/null +++ b/snes/memory/memory.hpp @@ -0,0 +1,74 @@ +struct Memory { + virtual inline unsigned size() const; + virtual uint8 read(unsigned addr) = 0; + virtual void write(unsigned addr, uint8 data) = 0; +}; + +struct StaticRAM : Memory { + inline uint8* data(); + inline unsigned size() const; + + inline uint8 read(unsigned addr); + inline void write(unsigned addr, uint8 n); + inline uint8& operator[](unsigned addr); + inline const uint8& operator[](unsigned addr) const; + + inline StaticRAM(unsigned size); + inline ~StaticRAM(); + +private: + uint8 *data_; + unsigned size_; +}; + +struct MappedRAM : Memory { + inline void reset(); + inline void map(uint8*, unsigned); + inline void copy(const uint8*, unsigned); + + inline void write_protect(bool status); + inline uint8* data(); + inline unsigned size() const; + + inline uint8 read(unsigned addr); + inline void write(unsigned addr, uint8 n); + inline const uint8& operator[](unsigned addr) const; + inline MappedRAM(); + +private: + uint8 *data_; + unsigned size_; + bool write_protect_; +}; + +struct Bus { + unsigned mirror(unsigned addr, unsigned size); + + alwaysinline uint8 read(unsigned addr); + alwaysinline void write(unsigned addr, uint8 data); + + uint8 *lookup; + uint32 *target; + + unsigned idcount; + function reader[256]; + function writer[256]; + + enum class MapMode : unsigned { Direct, Linear, Shadow }; + void map( + MapMode mode, + unsigned bank_lo, unsigned bank_hi, + unsigned addr_lo, unsigned addr_hi, + const function &read, + const function &write, + unsigned base = 0, unsigned length = 0 + ); + + void map_reset(); + void map_xml(); + + Bus(); + ~Bus(); +}; + +extern Bus bus; diff --git a/snes/ppu/background/background.cpp b/snes/ppu/background/background.cpp new file mode 100755 index 00000000..cb3544cb --- /dev/null +++ b/snes/ppu/background/background.cpp @@ -0,0 +1,278 @@ +#ifdef PPU_CPP + +#include "mode7.cpp" + +//V = 0, H = 0 +void PPU::Background::frame() { +} + +//H = 0 +void PPU::Background::scanline() { +} + +//H = 60 +void PPU::Background::begin() { + bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); + x = -7; + y = self.vcounter(); + + if(y == 1) { + mosaic.vcounter = regs.mosaic + 1; + mosaic.voffset = 1; + cache.hoffset = regs.hoffset; + cache.voffset = regs.voffset; + } else if(--mosaic.vcounter == 0) { + mosaic.vcounter = regs.mosaic + 1; + mosaic.voffset += regs.mosaic + 1; + cache.hoffset = regs.hoffset; + cache.voffset = regs.voffset; + } + + tile_counter = (7 - (cache.hoffset & 7)) << hires; + for(unsigned n = 0; n < 8; n++) data[n] = 0; + + mosaic.hcounter = regs.mosaic + 1; + mosaic.hoffset = 0; + + if(regs.mode == Mode::Mode7) return begin_mode7(); + if(regs.mosaic == 0) { + cache.hoffset = regs.hoffset; + cache.voffset = regs.voffset; + } +} + +void PPU::Background::get_tile() { + bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); + + unsigned color_depth = (regs.mode == Mode::BPP2 ? 0 : regs.mode == Mode::BPP4 ? 1 : 2); + unsigned palette_offset = (self.regs.bgmode == 0 ? id << 5 : 0); + unsigned palette_size = 2 << color_depth; + unsigned tile_mask = 0x0fff >> color_depth; + unsigned tiledata_index = regs.tiledata_addr >> (4 + color_depth); + + unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4); + unsigned tile_width = (!hires ? tile_height : 4); + + unsigned width = 256 << hires; + + unsigned hmask = (tile_height == 3 ? width : width << 1); + unsigned vmask = hmask; + if(regs.screen_size & 1) hmask <<= 1; + if(regs.screen_size & 2) vmask <<= 1; + hmask--; + vmask--; + + unsigned px = x << hires; + unsigned py = (regs.mosaic == 0 ? y : mosaic.voffset); + + unsigned hscroll = cache.hoffset; + unsigned vscroll = cache.voffset; + if(hires) { + hscroll <<= 1; + if(self.regs.interlace) py = (py << 1) + self.field(); + } + + unsigned hoffset = hscroll + px; + unsigned voffset = vscroll + py; + + if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) { + uint16 offset_x = (x + (hscroll & 7)); + + if(offset_x >= 8) { + unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.cache.hoffset & ~7), self.bg3.cache.voffset + 0); + unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.cache.hoffset & ~7), self.bg3.cache.voffset + 8); + unsigned valid_mask = (id == ID::BG1 ? 0x2000 : 0x4000); + + if(self.regs.bgmode == 4) { + if(hval & valid_mask) { + if((hval & 0x8000) == 0) { + hoffset = offset_x + (hval & ~7); + } else { + voffset = y + hval; + } + } + } else { + if(hval & valid_mask) hoffset = offset_x + (hval & ~7); + if(vval & valid_mask) voffset = y + vval; + } + } + } + + hoffset &= hmask; + voffset &= vmask; + + unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0); + unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0); + if(regs.screen_size == 3) screen_y <<= 1; + + unsigned tx = hoffset >> tile_width; + unsigned ty = voffset >> tile_height; + + uint16 offset = ((ty & 0x1f) << 5) + (tx & 0x1f); + if(tx & 0x20) offset += screen_x; + if(ty & 0x20) offset += screen_y; + + uint16 addr = regs.screen_addr + (offset << 1); + tile = (ppu.vram[addr + 0] << 0) + (ppu.vram[addr + 1] << 8); + bool mirror_y = tile & 0x8000; + bool mirror_x = tile & 0x4000; + priority = (tile & 0x2000 ? regs.priority1 : regs.priority0); + palette_number = (tile >> 10) & 7; + palette_index = palette_offset + (palette_number << palette_size); + + if(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile += 1; + if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile += 16; + uint16 character = ((tile & 0x03ff) + tiledata_index) & tile_mask; + + if(mirror_y) voffset ^= 7; + offset = (character << (4 + color_depth)) + ((voffset & 7) << 1); + + if(regs.mode >= Mode::BPP2) { + data[0] = ppu.vram[offset + 0]; + data[1] = ppu.vram[offset + 1]; + } + if(regs.mode >= Mode::BPP4) { + data[2] = ppu.vram[offset + 16]; + data[3] = ppu.vram[offset + 17]; + } + if(regs.mode >= Mode::BPP8) { + data[4] = ppu.vram[offset + 32]; + data[5] = ppu.vram[offset + 33]; + data[6] = ppu.vram[offset + 48]; + data[7] = ppu.vram[offset + 49]; + } + + if(mirror_x) for(unsigned n = 0; n < 8; n++) { + //reverse data bits in data[n]: 01234567 -> 76543210 + data[n] = ((data[n] >> 4) & 0x0f) | ((data[n] << 4) & 0xf0); + data[n] = ((data[n] >> 2) & 0x33) | ((data[n] << 2) & 0xcc); + data[n] = ((data[n] >> 1) & 0x55) | ((data[n] << 1) & 0xaa); + } +} + +void PPU::Background::run(bool screen) { + if(self.vcounter() == 0) return; + bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); + + if(screen == Screen::Sub) { + output.main.priority = 0; + output.sub.priority = 0; + if(hires == false) return; + } + + if(regs.main_enable == false && regs.sub_enable == false) return; + if(regs.mode == Mode::Inactive) return; + if(regs.mode == Mode::Mode7) return run_mode7(); + + if(tile_counter-- == 0) { + tile_counter = 7; + get_tile(); + } + + uint8 palette = get_tile_color(); + if(x == 0) mosaic.hcounter = 1; + if(x >= 0 && --mosaic.hcounter == 0) { + mosaic.hcounter = regs.mosaic + 1; + mosaic.priority = priority; + mosaic.palette = palette ? palette_index + palette : 0; + mosaic.tile = tile; + } + if(screen == Screen::Main) x++; + if(mosaic.palette == 0) return; + + if(hires == false || screen == Screen::Main) if(regs.main_enable) output.main = mosaic; + if(hires == false || screen == Screen::Sub ) if(regs.sub_enable ) output.sub = mosaic; +} + +unsigned PPU::Background::get_tile_color() { + unsigned color = 0; + if(regs.mode >= Mode::BPP2) { + color += (data[0] & 0x80) ? 0x01 : 0; data[0] <<= 1; + color += (data[1] & 0x80) ? 0x02 : 0; data[1] <<= 1; + } + if(regs.mode >= Mode::BPP4) { + color += (data[2] & 0x80) ? 0x04 : 0; data[2] <<= 1; + color += (data[3] & 0x80) ? 0x08 : 0; data[3] <<= 1; + } + if(regs.mode >= Mode::BPP8) { + color += (data[4] & 0x80) ? 0x10 : 0; data[4] <<= 1; + color += (data[5] & 0x80) ? 0x20 : 0; data[5] <<= 1; + color += (data[6] & 0x80) ? 0x40 : 0; data[6] <<= 1; + color += (data[7] & 0x80) ? 0x80 : 0; data[7] <<= 1; + } + return color; +} + +void PPU::Background::reset() { + regs.tiledata_addr = random(0x0000); + regs.screen_addr = random(0x0000); + regs.screen_size = random(0); + regs.mosaic = random(0); + regs.tile_size = random(0); + regs.mode = 0; + regs.priority0 = 0; + regs.priority1 = 0; + regs.main_enable = random(0); + regs.sub_enable = random(0); + regs.hoffset = random(0x0000); + regs.voffset = random(0x0000); + + cache.hoffset = 0; + cache.voffset = 0; + + output.main.palette = 0; + output.main.priority = 0; + output.sub.palette = 0; + output.sub.priority = 0; + + mosaic.priority = 0; + mosaic.palette = 0; + mosaic.tile = 0; + + mosaic.vcounter = 0; + mosaic.voffset = 0; + mosaic.hcounter = 0; + mosaic.hoffset = 0; + + x = 0; + y = 0; + + tile_counter = 0; + tile = 0; + priority = 0; + palette_number = 0; + palette_index = 0; + for(unsigned n = 0; n < 8; n++) data[n] = 0; +} + +unsigned PPU::Background::get_tile(unsigned x, unsigned y) { + bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); + unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4); + unsigned tile_width = (!hires ? tile_height : 4); + unsigned width = (!hires ? 256 : 512); + unsigned mask_x = (tile_height == 3 ? width : width << 1); + unsigned mask_y = mask_x; + if(regs.screen_size & 1) mask_x <<= 1; + if(regs.screen_size & 2) mask_y <<= 1; + mask_x--; + mask_y--; + + unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0); + unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0); + if(regs.screen_size == 3) screen_y <<= 1; + + x = (x & mask_x) >> tile_width; + y = (y & mask_y) >> tile_height; + + uint16 offset = ((y & 0x1f) << 5) + (x & 0x1f); + if(x & 0x20) offset += screen_x; + if(y & 0x20) offset += screen_y; + + uint16 addr = regs.screen_addr + (offset << 1); + return (ppu.vram[addr + 0] << 0) + (ppu.vram[addr + 1] << 8); +} + +PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) { +} + +#endif diff --git a/snes/ppu/background/background.hpp b/snes/ppu/background/background.hpp new file mode 100755 index 00000000..26553af4 --- /dev/null +++ b/snes/ppu/background/background.hpp @@ -0,0 +1,78 @@ +class Background { + struct ID { enum { BG1, BG2, BG3, BG4 }; }; + unsigned id; + + struct Mode { enum { BPP2, BPP4, BPP8, Mode7, Inactive }; }; + struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; }; + struct TileSize { enum { Size8x8, Size16x16 }; }; + struct Screen { enum { Main, Sub }; }; + + struct Regs { + uint16 tiledata_addr; + uint16 screen_addr; + uint2 screen_size; + uint4 mosaic; + bool tile_size; + + unsigned mode; + unsigned priority0; + unsigned priority1; + + bool main_enable; + bool sub_enable; + + uint16 hoffset; + uint16 voffset; + } regs; + + struct Cache { + uint16 hoffset; + uint16 voffset; + } cache; + + struct Output { + struct Pixel { + unsigned priority; //0 = none (transparent) + uint8 palette; + uint16 tile; + } main, sub; + } output; + + struct Mosaic : Output::Pixel { + unsigned vcounter; + unsigned voffset; + unsigned hcounter; + unsigned hoffset; + } mosaic; + + struct { + signed x; + signed y; + + unsigned tile_counter; + unsigned tile; + unsigned priority; + unsigned palette_number; + unsigned palette_index; + uint8 data[8]; + }; + + void frame(); + void scanline(); + void begin(); + void run(bool screen); + void reset(); + + void get_tile(); + unsigned get_tile_color(); + unsigned get_tile(unsigned x, unsigned y); + signed clip(signed n); + void begin_mode7(); + void run_mode7(); + + void serialize(serializer&); + Background(PPU &self, unsigned id); + + PPU &self; + friend class PPU; +}; diff --git a/snes/ppu/background/mode7.cpp b/snes/ppu/background/mode7.cpp new file mode 100755 index 00000000..bb630647 --- /dev/null +++ b/snes/ppu/background/mode7.cpp @@ -0,0 +1,110 @@ +#ifdef PPU_CPP + +signed PPU::Background::clip(signed n) { + //13-bit sign extend: --s---nnnnnnnnnn -> ssssssnnnnnnnnnn + return n & 0x2000 ? (n | ~1023) : (n & 1023); +} + +//H = 60 +void PPU::Background::begin_mode7() { + cache.hoffset = self.regs.mode7_hoffset; + cache.voffset = self.regs.mode7_voffset; +} + +void PPU::Background::run_mode7() { + signed a = sclip<16>(self.regs.m7a); + signed b = sclip<16>(self.regs.m7b); + signed c = sclip<16>(self.regs.m7c); + signed d = sclip<16>(self.regs.m7d); + + signed cx = sclip<13>(self.regs.m7x); + signed cy = sclip<13>(self.regs.m7y); + signed hoffset = sclip<13>(cache.hoffset); + signed voffset = sclip<13>(cache.voffset); + + if(Background::x++ & ~255) return; + unsigned x = mosaic.hoffset; + unsigned y = self.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size + + if(--mosaic.hcounter == 0) { + mosaic.hcounter = regs.mosaic + 1; + mosaic.hoffset += regs.mosaic + 1; + } + + if(self.regs.mode7_hflip) x = 255 - x; + if(self.regs.mode7_vflip) y = 255 - y; + + signed psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8); + signed psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8); + + signed px = psx + (a * x); + signed py = psy + (c * x); + + //mask pseudo-FP bits + px >>= 8; + py >>= 8; + + unsigned tile; + unsigned palette; + switch(self.regs.mode7_repeat) { + //screen repetition outside of screen area + case 0: + case 1: { + px &= 1023; + py &= 1023; + tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; + palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + break; + } + + //palette color 0 outside of screen area + case 2: { + if((px | py) & ~1023) { + palette = 0; + } else { + px &= 1023; + py &= 1023; + tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; + palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + } + break; + } + + //character 0 repetition outside of screen area + case 3: { + if((px | py) & ~1023) { + tile = 0; + } else { + px &= 1023; + py &= 1023; + tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; + } + palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + break; + } + } + + unsigned priority; + if(id == ID::BG1) { + priority = regs.priority0; + } else if(id == ID::BG2) { + priority = (palette & 0x80 ? regs.priority1 : regs.priority0); + palette &= 0x7f; + } + + if(palette == 0) return; + + if(regs.main_enable) { + output.main.palette = palette; + output.main.priority = priority; + output.main.tile = 0; + } + + if(regs.sub_enable) { + output.sub.palette = palette; + output.sub.priority = priority; + output.sub.tile = 0; + } +} + +#endif diff --git a/snes/ppu/counter/counter-inline.hpp b/snes/ppu/counter/counter-inline.hpp new file mode 100755 index 00000000..2c21b6d1 --- /dev/null +++ b/snes/ppu/counter/counter-inline.hpp @@ -0,0 +1,85 @@ +//this should only be called by CPU::PPUcounter::tick(); +//keeps track of previous counter positions in history table +void PPUcounter::tick() { + status.hcounter += 2; //increment by smallest unit of time + if(status.hcounter >= 1360 && status.hcounter == lineclocks()) { + status.hcounter = 0; + vcounter_tick(); + } + + history.index = (history.index + 1) & 2047; + history.field [history.index] = status.field; + history.vcounter[history.index] = status.vcounter; + history.hcounter[history.index] = status.hcounter; +} + +//this should only be called by PPU::PPUcounter::tick(n); +//allows stepping by more than the smallest unit of time +void PPUcounter::tick(unsigned clocks) { + status.hcounter += clocks; + if(status.hcounter >= lineclocks()) { + status.hcounter -= lineclocks(); + vcounter_tick(); + } +} + +//internal +void PPUcounter::vcounter_tick() { + if(++status.vcounter == 128) status.interlace = ppu.interlace(); + + if((system.region() == System::Region::NTSC && status.interlace == false && status.vcounter == 262) + || (system.region() == System::Region::NTSC && status.interlace == true && status.vcounter == 263) + || (system.region() == System::Region::NTSC && status.interlace == true && status.vcounter == 262 && status.field == 1) + || (system.region() == System::Region::PAL && status.interlace == false && status.vcounter == 312) + || (system.region() == System::Region::PAL && status.interlace == true && status.vcounter == 313) + || (system.region() == System::Region::PAL && status.interlace == true && status.vcounter == 312 && status.field == 1) + ) { + status.vcounter = 0; + status.field = !status.field; + } + if(scanline) scanline(); +} + +bool PPUcounter::field () const { return status.field; } +uint16 PPUcounter::vcounter() const { return status.vcounter; } +uint16 PPUcounter::hcounter() const { return status.hcounter; } + +bool PPUcounter::field (unsigned offset) const { return history.field [(history.index - (offset >> 1)) & 2047]; } +uint16 PPUcounter::vcounter(unsigned offset) const { return history.vcounter[(history.index - (offset >> 1)) & 2047]; } +uint16 PPUcounter::hcounter(unsigned offset) const { return history.hcounter[(history.index - (offset >> 1)) & 2047]; } + +//one PPU dot = 4 CPU clocks +// +//PPU dots 323 and 327 are 6 CPU clocks long. +//this does not apply to NTSC non-interlace scanline 240 on odd fields. this is +//because the PPU skips one dot to alter the color burst phase of the video signal. +// +//dot 323 range = { 1292, 1294, 1296 } +//dot 327 range = { 1310, 1312, 1314 } + +uint16 PPUcounter::hdot() const { + if(system.region() == System::Region::NTSC && status.interlace == false && vcounter() == 240 && field() == 1) { + return (hcounter() >> 2); + } else { + return (hcounter() - ((hcounter() > 1292) << 1) - ((hcounter() > 1310) << 1)) >> 2; + } +} + +uint16 PPUcounter::lineclocks() const { + if(system.region() == System::Region::NTSC && status.interlace == false && vcounter() == 240 && field() == 1) return 1360; + return 1364; +} + +void PPUcounter::reset() { + status.interlace = false; + status.field = 0; + status.vcounter = 0; + status.hcounter = 0; + history.index = 0; + + for(unsigned i = 0; i < 2048; i++) { + history.field [i] = 0; + history.vcounter[i] = 0; + history.hcounter[i] = 0; + } +} diff --git a/snes/ppu/counter/counter.hpp b/snes/ppu/counter/counter.hpp new file mode 100755 index 00000000..b8d7aa7e --- /dev/null +++ b/snes/ppu/counter/counter.hpp @@ -0,0 +1,49 @@ +//PPUcounter emulates the H/V latch counters of the S-PPU2. +// +//real hardware has the S-CPU maintain its own copy of these counters that are +//updated based on the state of the S-PPU Vblank and Hblank pins. emulating this +//would require full lock-step synchronization for every clock tick. +//to bypass this and allow the two to run out-of-order, both the CPU and PPU +//classes inherit PPUcounter and keep their own counters. +//the timers are kept in sync, as the only differences occur on V=240 and V=261, +//based on interlace. thus, we need only synchronize and fetch interlace at any +//point before this in the frame, which is handled internally by this class at +//V=128. + +class PPUcounter { +public: + alwaysinline void tick(); + alwaysinline void tick(unsigned clocks); + + alwaysinline bool field () const; + alwaysinline uint16 vcounter() const; + alwaysinline uint16 hcounter() const; + inline uint16 hdot() const; + inline uint16 lineclocks() const; + + alwaysinline bool field (unsigned offset) const; + alwaysinline uint16 vcounter(unsigned offset) const; + alwaysinline uint16 hcounter(unsigned offset) const; + + inline void reset(); + function scanline; + void serialize(serializer&); + +private: + inline void vcounter_tick(); + + struct { + bool interlace; + bool field; + uint16 vcounter; + uint16 hcounter; + } status; + + struct { + bool field[2048]; + uint16 vcounter[2048]; + uint16 hcounter[2048]; + + int32 index; + } history; +}; diff --git a/snes/ppu/debugger/debugger.cpp b/snes/ppu/debugger/debugger.cpp new file mode 100755 index 00000000..28a519fc --- /dev/null +++ b/snes/ppu/debugger/debugger.cpp @@ -0,0 +1,17 @@ +#ifdef PPU_CPP + +bool PPUDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + #undef item + return false; +} + +#endif diff --git a/snes/ppu/debugger/debugger.hpp b/snes/ppu/debugger/debugger.hpp new file mode 100755 index 00000000..9ce6a4e6 --- /dev/null +++ b/snes/ppu/debugger/debugger.hpp @@ -0,0 +1,4 @@ +class PPUDebugger : public PPU, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); +}; diff --git a/snes/ppu/mmio/mmio.cpp b/snes/ppu/mmio/mmio.cpp new file mode 100755 index 00000000..302f74f8 --- /dev/null +++ b/snes/ppu/mmio/mmio.cpp @@ -0,0 +1,865 @@ +#ifdef PPU_CPP + +bool PPU::interlace() const { + return display.interlace; +} + +bool PPU::overscan() const { + return display.overscan; +} + +bool PPU::hires() const { + return true; +} + +void PPU::latch_counters() { + cpu.synchronize_ppu(); + regs.hcounter = hdot(); + regs.vcounter = vcounter(); + regs.counters_latched = true; +} + +uint16 PPU::get_vram_address() { + uint16 addr = regs.vram_addr; + switch(regs.vram_mapping) { + case 0: break; //direct mapping + case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break; + case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break; + case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break; + } + return (addr << 1); +} + +uint8 PPU::vram_read(unsigned addr) { + if(regs.display_disable || vcounter() >= (!regs.overscan ? 225 : 240)) { + return vram[addr]; + } + return 0x00; +} + +void PPU::vram_write(unsigned addr, uint8 data) { + if(regs.display_disable || vcounter() >= (!regs.overscan ? 225 : 240)) { + vram[addr] = data; + } +} + +void PPU::mmio_update_video_mode() { + switch(regs.bgmode) { + case 0: { + bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11; + bg2.regs.mode = Background::Mode::BPP2; bg2.regs.priority0 = 7; bg2.regs.priority1 = 10; + bg3.regs.mode = Background::Mode::BPP2; bg3.regs.priority0 = 2; bg3.regs.priority1 = 5; + bg4.regs.mode = Background::Mode::BPP2; bg4.regs.priority0 = 1; bg4.regs.priority1 = 4; + sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12; + } break; + + case 1: { + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::BPP2; + bg4.regs.mode = Background::Mode::Inactive; + if(regs.bg3_priority) { + bg1.regs.priority0 = 5; bg1.regs.priority1 = 8; + bg2.regs.priority0 = 4; bg2.regs.priority1 = 7; + bg3.regs.priority0 = 1; bg3.regs.priority1 = 10; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 3; sprite.regs.priority2 = 6; sprite.regs.priority3 = 9; + } else { + bg1.regs.priority0 = 6; bg1.regs.priority1 = 9; + bg2.regs.priority0 = 5; bg2.regs.priority1 = 8; + bg3.regs.priority0 = 1; bg3.regs.priority1 = 3; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10; + } + } break; + + case 2: { + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + } break; + + case 3: { + bg1.regs.mode = Background::Mode::BPP8; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + } break; + + case 4: { + bg1.regs.mode = Background::Mode::BPP8; + bg2.regs.mode = Background::Mode::BPP2; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + } break; + + case 5: { + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP2; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + } break; + + case 6: { + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::Inactive; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 2; bg1.regs.priority1 = 5; + sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6; + } break; + + case 7: { + if(regs.mode7_extbg == false) { + bg1.regs.mode = Background::Mode::Mode7; + bg2.regs.mode = Background::Mode::Inactive; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 2; bg1.regs.priority1 = 2; + sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 5; + } else { + bg1.regs.mode = Background::Mode::Mode7; + bg2.regs.mode = Background::Mode::Mode7; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 3; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7; + } + } break; + } +} + +//INIDISP +void PPU::mmio_w2100(uint8 data) { + if(regs.display_disable && vcounter() == (!regs.overscan ? 225 : 240)) sprite.address_reset(); + regs.display_disable = data & 0x80; + regs.display_brightness = data & 0x0f; +} + +//OBSEL +void PPU::mmio_w2101(uint8 data) { + sprite.regs.base_size = (data >> 5) & 7; + sprite.regs.nameselect = (data >> 3) & 3; + sprite.regs.tiledata_addr = (data & 3) << 14; +} + +//OAMADDL +void PPU::mmio_w2102(uint8 data) { + regs.oam_baseaddr = (regs.oam_baseaddr & 0x0200) | (data << 1); + sprite.address_reset(); +} + +//OAMADDH +void PPU::mmio_w2103(uint8 data) { + regs.oam_priority = data & 0x80; + regs.oam_baseaddr = ((data & 0x01) << 9) | (regs.oam_baseaddr & 0x01fe); + sprite.address_reset(); +} + +//OAMDATA +void PPU::mmio_w2104(uint8 data) { + bool latch = regs.oam_addr & 1; + uint10 addr = regs.oam_addr++; + if(regs.display_disable == false && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.oam_iaddr; + if(addr & 0x0200) addr &= 0x021f; + + if(latch == 0) regs.oam_latchdata = data; + if(addr & 0x0200) { + sprite.update(addr, data); + } else if(latch == 1) { + sprite.update((addr & ~1) + 0, regs.oam_latchdata); + sprite.update((addr & ~1) + 1, data); + } + sprite.set_first_sprite(); +} + +//BGMODE +void PPU::mmio_w2105(uint8 data) { + bg4.regs.tile_size = (data & 0x80); + bg3.regs.tile_size = (data & 0x40); + bg2.regs.tile_size = (data & 0x20); + bg1.regs.tile_size = (data & 0x10); + regs.bg3_priority = (data & 0x08); + regs.bgmode = (data & 0x07); + mmio_update_video_mode(); +} + +//MOSAIC +void PPU::mmio_w2106(uint8 data) { + unsigned mosaic_size = (data >> 4) & 15; + bg4.regs.mosaic = (data & 0x08 ? mosaic_size : 0); + bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0); + bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0); + bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0); +} + +//BG1SC +void PPU::mmio_w2107(uint8 data) { + bg1.regs.screen_addr = (data & 0x7c) << 9; + bg1.regs.screen_size = data & 3; +} + +//BG2SC +void PPU::mmio_w2108(uint8 data) { + bg2.regs.screen_addr = (data & 0x7c) << 9; + bg2.regs.screen_size = data & 3; +} + +//BG3SC +void PPU::mmio_w2109(uint8 data) { + bg3.regs.screen_addr = (data & 0x7c) << 9; + bg3.regs.screen_size = data & 3; +} + +//BG4SC +void PPU::mmio_w210a(uint8 data) { + bg4.regs.screen_addr = (data & 0x7c) << 9; + bg4.regs.screen_size = data & 3; +} + +//BG12NBA +void PPU::mmio_w210b(uint8 data) { + bg1.regs.tiledata_addr = (data & 0x07) << 13; + bg2.regs.tiledata_addr = (data & 0x70) << 9; +} + +//BG34NBA +void PPU::mmio_w210c(uint8 data) { + bg3.regs.tiledata_addr = (data & 0x07) << 13; + bg4.regs.tiledata_addr = (data & 0x70) << 9; +} + +//BG1HOFS +void PPU::mmio_w210d(uint8 data) { + regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + + bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; +} + +//BG1VOFS +void PPU::mmio_w210e(uint8 data) { + regs.mode7_voffset = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + + bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; +} + +//BG2HOFS +void PPU::mmio_w210f(uint8 data) { + bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; +} + +//BG2VOFS +void PPU::mmio_w2110(uint8 data) { + bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; +} + +//BG3HOFS +void PPU::mmio_w2111(uint8 data) { + bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; +} + +//BG3VOFS +void PPU::mmio_w2112(uint8 data) { + bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; +} + +//BG4HOFS +void PPU::mmio_w2113(uint8 data) { + bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; +} + +//BG4VOFS +void PPU::mmio_w2114(uint8 data) { + bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; +} + +//VMAIN +void PPU::mmio_w2115(uint8 data) { + regs.vram_incmode = data & 0x80; + regs.vram_mapping = (data >> 2) & 3; + switch(data & 3) { + case 0: regs.vram_incsize = 1; break; + case 1: regs.vram_incsize = 32; break; + case 2: regs.vram_incsize = 128; break; + case 3: regs.vram_incsize = 128; break; + } +} + +//VMADDL +void PPU::mmio_w2116(uint8 data) { + regs.vram_addr &= 0xff00; + regs.vram_addr |= (data << 0); + uint16 addr = get_vram_address(); + regs.vram_readbuffer = vram_read(addr + 0) << 0; + regs.vram_readbuffer |= vram_read(addr + 1) << 8; +} + +//VMADDH +void PPU::mmio_w2117(uint8 data) { + regs.vram_addr &= 0x00ff; + regs.vram_addr |= (data << 8); + uint16 addr = get_vram_address(); + regs.vram_readbuffer = vram_read(addr + 0) << 0; + regs.vram_readbuffer |= vram_read(addr + 1) << 8; +} + +//VMDATAL +void PPU::mmio_w2118(uint8 data) { + uint16 addr = get_vram_address() + 0; + vram_write(addr, data); + if(regs.vram_incmode == 0) regs.vram_addr += regs.vram_incsize; +} + +//VMDATAH +void PPU::mmio_w2119(uint8 data) { + uint16 addr = get_vram_address() + 1; + vram_write(addr, data); + if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize; +} + +//M7SEL +void PPU::mmio_w211a(uint8 data) { + regs.mode7_repeat = (data >> 6) & 3; + regs.mode7_vflip = data & 0x02; + regs.mode7_hflip = data & 0x01; +} + +//M7A +void PPU::mmio_w211b(uint8 data) { + regs.m7a = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; +} + +//M7B +void PPU::mmio_w211c(uint8 data) { + regs.m7b = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; +} + +//M7C +void PPU::mmio_w211d(uint8 data) { + regs.m7c = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; +} + +//M7D +void PPU::mmio_w211e(uint8 data) { + regs.m7d = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; +} + +//M7X +void PPU::mmio_w211f(uint8 data) { + regs.m7x = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; +} + +//M7Y +void PPU::mmio_w2120(uint8 data) { + regs.m7y = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; +} + +//CGADD +void PPU::mmio_w2121(uint8 data) { + regs.cgram_addr = data << 1; +} + +//CGDATA +void PPU::mmio_w2122(uint8 data) { + bool latch = regs.cgram_addr & 1; + uint9 addr = regs.cgram_addr++; + if(regs.display_disable == false + && vcounter() > 0 && vcounter() < (!regs.overscan ? 225 : 240) + && hcounter() >= 88 && hcounter() < 1096 + ) addr = regs.cgram_iaddr; + + if(latch == 0) { + regs.cgram_latchdata = data; + } else { + cgram[(addr & ~1) + 0] = regs.cgram_latchdata; + cgram[(addr & ~1) + 1] = data & 0x7f; + } +} + +//W12SEL +void PPU::mmio_w2123(uint8 data) { + window.regs.bg2_two_enable = data & 0x80; + window.regs.bg2_two_invert = data & 0x40; + window.regs.bg2_one_enable = data & 0x20; + window.regs.bg2_one_invert = data & 0x10; + window.regs.bg1_two_enable = data & 0x08; + window.regs.bg1_two_invert = data & 0x04; + window.regs.bg1_one_enable = data & 0x02; + window.regs.bg1_one_invert = data & 0x01; +} + +//W34SEL +void PPU::mmio_w2124(uint8 data) { + window.regs.bg4_two_enable = data & 0x80; + window.regs.bg4_two_invert = data & 0x40; + window.regs.bg4_one_enable = data & 0x20; + window.regs.bg4_one_invert = data & 0x10; + window.regs.bg3_two_enable = data & 0x08; + window.regs.bg3_two_invert = data & 0x04; + window.regs.bg3_one_enable = data & 0x02; + window.regs.bg3_one_invert = data & 0x01; +} + +//WOBJSEL +void PPU::mmio_w2125(uint8 data) { + window.regs.col_two_enable = data & 0x80; + window.regs.col_two_invert = data & 0x40; + window.regs.col_one_enable = data & 0x20; + window.regs.col_one_invert = data & 0x10; + window.regs.oam_two_enable = data & 0x08; + window.regs.oam_two_invert = data & 0x04; + window.regs.oam_one_enable = data & 0x02; + window.regs.oam_one_invert = data & 0x01; +} + +//WH0 +void PPU::mmio_w2126(uint8 data) { + window.regs.one_left = data; +} + +//WH1 +void PPU::mmio_w2127(uint8 data) { + window.regs.one_right = data; +} + +//WH2 +void PPU::mmio_w2128(uint8 data) { + window.regs.two_left = data; +} + +//WH3 +void PPU::mmio_w2129(uint8 data) { + window.regs.two_right = data; +} + +//WBGLOG +void PPU::mmio_w212a(uint8 data) { + window.regs.bg4_mask = (data >> 6) & 3; + window.regs.bg3_mask = (data >> 4) & 3; + window.regs.bg2_mask = (data >> 2) & 3; + window.regs.bg1_mask = (data >> 0) & 3; +} + +//WOBJLOG +void PPU::mmio_w212b(uint8 data) { + window.regs.col_mask = (data >> 2) & 3; + window.regs.oam_mask = (data >> 0) & 3; +} + +//TM +void PPU::mmio_w212c(uint8 data) { + sprite.regs.main_enable = data & 0x10; + bg4.regs.main_enable = data & 0x08; + bg3.regs.main_enable = data & 0x04; + bg2.regs.main_enable = data & 0x02; + bg1.regs.main_enable = data & 0x01; +} + +//TS +void PPU::mmio_w212d(uint8 data) { + sprite.regs.sub_enable = data & 0x10; + bg4.regs.sub_enable = data & 0x08; + bg3.regs.sub_enable = data & 0x04; + bg2.regs.sub_enable = data & 0x02; + bg1.regs.sub_enable = data & 0x01; +} + +//TMW +void PPU::mmio_w212e(uint8 data) { + window.regs.oam_main_enable = data & 0x10; + window.regs.bg4_main_enable = data & 0x08; + window.regs.bg3_main_enable = data & 0x04; + window.regs.bg2_main_enable = data & 0x02; + window.regs.bg1_main_enable = data & 0x01; +} + +//TSW +void PPU::mmio_w212f(uint8 data) { + window.regs.oam_sub_enable = data & 0x10; + window.regs.bg4_sub_enable = data & 0x08; + window.regs.bg3_sub_enable = data & 0x04; + window.regs.bg2_sub_enable = data & 0x02; + window.regs.bg1_sub_enable = data & 0x01; +} + +//CGWSEL +void PPU::mmio_w2130(uint8 data) { + window.regs.col_main_mask = (data >> 6) & 3; + window.regs.col_sub_mask = (data >> 4) & 3; + screen.regs.addsub_mode = data & 0x02; + screen.regs.direct_color = data & 0x01; +} + +//CGADDSUB +void PPU::mmio_w2131(uint8 data) { + screen.regs.color_mode = data & 0x80; + screen.regs.color_halve = data & 0x40; + screen.regs.back_color_enable = data & 0x20; + screen.regs.oam_color_enable = data & 0x10; + screen.regs.bg4_color_enable = data & 0x08; + screen.regs.bg3_color_enable = data & 0x04; + screen.regs.bg2_color_enable = data & 0x02; + screen.regs.bg1_color_enable = data & 0x01; +} + +//COLDATA +void PPU::mmio_w2132(uint8 data) { + if(data & 0x80) screen.regs.color_b = data & 0x1f; + if(data & 0x40) screen.regs.color_g = data & 0x1f; + if(data & 0x20) screen.regs.color_r = data & 0x1f; +} + +//SETINI +void PPU::mmio_w2133(uint8 data) { + regs.mode7_extbg = data & 0x40; + regs.pseudo_hires = data & 0x08; + regs.overscan = data & 0x04; + sprite.regs.interlace = data & 0x02; + regs.interlace = data & 0x01; + mmio_update_video_mode(); +} + +//MPYL +uint8 PPU::mmio_r2134() { + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = (result >> 0); + return regs.ppu1_mdr; +} + +//MPYM +uint8 PPU::mmio_r2135() { + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = (result >> 8); + return regs.ppu1_mdr; +} + +//MPYH +uint8 PPU::mmio_r2136() { + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = (result >> 16); + return regs.ppu1_mdr; +} + +//SLHV +uint8 PPU::mmio_r2137() { + if(cpu.pio() & 0x80) latch_counters(); + return cpu.regs.mdr; +} + +//OAMDATAREAD +uint8 PPU::mmio_r2138() { + uint10 addr = regs.oam_addr++; + if(regs.display_disable == false && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.oam_iaddr; + if(addr & 0x0200) addr &= 0x021f; + + regs.ppu1_mdr = oam[addr]; + sprite.set_first_sprite(); + return regs.ppu1_mdr; +} + +//VMDATALREAD +uint8 PPU::mmio_r2139() { + uint16 addr = get_vram_address() + 0; + regs.ppu1_mdr = regs.vram_readbuffer >> 0; + if(regs.vram_incmode == 0) { + addr &= ~1; + regs.vram_readbuffer = vram_read(addr + 0) << 0; + regs.vram_readbuffer |= vram_read(addr + 1) << 8; + regs.vram_addr += regs.vram_incsize; + } + return regs.ppu1_mdr; +} + +//VMDATAHREAD +uint8 PPU::mmio_r213a() { + uint16 addr = get_vram_address() + 1; + regs.ppu1_mdr = regs.vram_readbuffer >> 8; + if(regs.vram_incmode == 1) { + addr &= ~1; + regs.vram_readbuffer = vram_read(addr + 0) << 0; + regs.vram_readbuffer |= vram_read(addr + 1) << 8; + regs.vram_addr += regs.vram_incsize; + } + return regs.ppu1_mdr; +} + +//CGDATAREAD +uint8 PPU::mmio_r213b() { + bool latch = regs.cgram_addr & 1; + uint9 addr = regs.cgram_addr++; + if(regs.display_disable == false + && vcounter() > 0 && vcounter() < (!regs.overscan ? 225 : 240) + && hcounter() >= 88 && hcounter() < 1096 + ) addr = regs.cgram_iaddr; + + if(latch == 0) { + regs.ppu2_mdr = cgram[addr]; + } else { + regs.ppu2_mdr &= 0x80; + regs.ppu2_mdr |= cgram[addr]; + } + return regs.ppu2_mdr; +} + +//OPHCT +uint8 PPU::mmio_r213c() { + if(regs.latch_hcounter == 0) { + regs.ppu2_mdr = (regs.hcounter >> 0); + } else { + regs.ppu2_mdr &= 0xfe; + regs.ppu2_mdr |= (regs.hcounter >> 8) & 1; + } + regs.latch_hcounter ^= 1; + return regs.ppu2_mdr; +} + +//OPVCT +uint8 PPU::mmio_r213d() { + if(regs.latch_vcounter == 0) { + regs.ppu2_mdr = (regs.vcounter >> 0); + } else { + regs.ppu2_mdr &= 0xfe; + regs.ppu2_mdr |= (regs.vcounter >> 8) & 1; + } + regs.latch_vcounter ^= 1; + return regs.ppu2_mdr; +} + +//STAT77 +uint8 PPU::mmio_r213e() { + regs.ppu1_mdr &= 0x10; + regs.ppu1_mdr |= sprite.regs.time_over << 7; + regs.ppu1_mdr |= sprite.regs.range_over << 6; + regs.ppu1_mdr |= ppu1_version & 0x0f; + return regs.ppu1_mdr; +} + +//STAT78 +uint8 PPU::mmio_r213f() { + regs.latch_hcounter = 0; + regs.latch_vcounter = 0; + + regs.ppu2_mdr &= 0x20; + regs.ppu2_mdr |= field() << 7; + if((cpu.pio() & 0x80) == 0) { + regs.ppu2_mdr |= 0x40; + } else if(regs.counters_latched) { + regs.ppu2_mdr |= 0x40; + regs.counters_latched = false; + } + regs.ppu2_mdr |= (system.region() == System::Region::NTSC ? 0 : 1) << 4; + regs.ppu2_mdr |= ppu2_version & 0x0f; + return regs.ppu2_mdr; +} + +void PPU::mmio_reset() { + regs.ppu1_mdr = random(0xff); + regs.ppu2_mdr = random(0xff); + + regs.vram_readbuffer = random(0x0000); + regs.oam_latchdata = random(0x00); + regs.cgram_latchdata = random(0x00); + regs.bgofs_latchdata = random(0x00); + regs.mode7_latchdata = random(0x00); + regs.counters_latched = false; + regs.latch_hcounter = 0; + regs.latch_vcounter = 0; + + regs.oam_iaddr = 0x0000; + regs.cgram_iaddr = 0x00; + + //$2100 INIDISP + regs.display_disable = true; + regs.display_brightness = 0; + + //$2102 OAMADDL + //$2103 OAMADDH + regs.oam_baseaddr = random(0x0000); + regs.oam_addr = random(0x0000); + regs.oam_priority = random(false); + + //$2105 BGMODE + regs.bg3_priority = false; + regs.bgmode = 0; + + //$210d BG1HOFS + regs.mode7_hoffset = random(0x0000); + + //$210e BG1VOFS + regs.mode7_voffset = random(0x0000); + + //$2115 VMAIN + regs.vram_incmode = random(1); + regs.vram_mapping = random(0); + regs.vram_incsize = 1; + + //$2116 VMADDL + //$2117 VMADDH + regs.vram_addr = random(0x0000); + + //$211a M7SEL + regs.mode7_repeat = random(0); + regs.mode7_vflip = random(false); + regs.mode7_hflip = random(false); + + //$211b M7A + regs.m7a = random(0x0000); + + //$211c M7B + regs.m7b = random(0x0000); + + //$211d M7C + regs.m7c = random(0x0000); + + //$211e M7D + regs.m7d = random(0x0000); + + //$211f M7X + regs.m7x = random(0x0000); + + //$2120 M7Y + regs.m7y = random(0x0000); + + //$2121 CGADD + regs.cgram_addr = random(0x0000); + + //$2133 SETINI + regs.mode7_extbg = random(false); + regs.pseudo_hires = random(false); + regs.overscan = false; + regs.interlace = false; + + //$213c OPHCT + regs.hcounter = 0; + + //$213d OPVCT + regs.vcounter = 0; +} + +uint8 PPU::mmio_read(unsigned addr) { + cpu.synchronize_ppu(); + + switch(addr & 0xffff) { + case 0x2104: + case 0x2105: + case 0x2106: + case 0x2108: + case 0x2109: + case 0x210a: + case 0x2114: + case 0x2115: + case 0x2116: + case 0x2118: + case 0x2119: + case 0x211a: + case 0x2124: + case 0x2125: + case 0x2126: + case 0x2128: + case 0x2129: + case 0x212a: return regs.ppu1_mdr; + case 0x2134: return mmio_r2134(); //MPYL + case 0x2135: return mmio_r2135(); //MPYM + case 0x2136: return mmio_r2136(); //MYPH + case 0x2137: return mmio_r2137(); //SLHV + case 0x2138: return mmio_r2138(); //OAMDATAREAD + case 0x2139: return mmio_r2139(); //VMDATALREAD + case 0x213a: return mmio_r213a(); //VMDATAHREAD + case 0x213b: return mmio_r213b(); //CGDATAREAD + case 0x213c: return mmio_r213c(); //OPHCT + case 0x213d: return mmio_r213d(); //OPVCT + case 0x213e: return mmio_r213e(); //STAT77 + case 0x213f: return mmio_r213f(); //STAT78 + } + + return cpu.regs.mdr; +} + +void PPU::mmio_write(unsigned addr, uint8 data) { + cpu.synchronize_ppu(); + + switch(addr & 0xffff) { + case 0x2100: return mmio_w2100(data); //INIDISP + case 0x2101: return mmio_w2101(data); //OBSEL + case 0x2102: return mmio_w2102(data); //OAMADDL + case 0x2103: return mmio_w2103(data); //OAMADDH + case 0x2104: return mmio_w2104(data); //OAMDATA + case 0x2105: return mmio_w2105(data); //BGMODE + case 0x2106: return mmio_w2106(data); //MOSAIC + case 0x2107: return mmio_w2107(data); //BG1SC + case 0x2108: return mmio_w2108(data); //BG2SC + case 0x2109: return mmio_w2109(data); //BG3SC + case 0x210a: return mmio_w210a(data); //BG4SC + case 0x210b: return mmio_w210b(data); //BG12NBA + case 0x210c: return mmio_w210c(data); //BG34NBA + case 0x210d: return mmio_w210d(data); //BG1HOFS + case 0x210e: return mmio_w210e(data); //BG1VOFS + case 0x210f: return mmio_w210f(data); //BG2HOFS + case 0x2110: return mmio_w2110(data); //BG2VOFS + case 0x2111: return mmio_w2111(data); //BG3HOFS + case 0x2112: return mmio_w2112(data); //BG3VOFS + case 0x2113: return mmio_w2113(data); //BG4HOFS + case 0x2114: return mmio_w2114(data); //BG4VOFS + case 0x2115: return mmio_w2115(data); //VMAIN + case 0x2116: return mmio_w2116(data); //VMADDL + case 0x2117: return mmio_w2117(data); //VMADDH + case 0x2118: return mmio_w2118(data); //VMDATAL + case 0x2119: return mmio_w2119(data); //VMDATAH + case 0x211a: return mmio_w211a(data); //M7SEL + case 0x211b: return mmio_w211b(data); //M7A + case 0x211c: return mmio_w211c(data); //M7B + case 0x211d: return mmio_w211d(data); //M7C + case 0x211e: return mmio_w211e(data); //M7D + case 0x211f: return mmio_w211f(data); //M7X + case 0x2120: return mmio_w2120(data); //M7Y + case 0x2121: return mmio_w2121(data); //CGADD + case 0x2122: return mmio_w2122(data); //CGDATA + case 0x2123: return mmio_w2123(data); //W12SEL + case 0x2124: return mmio_w2124(data); //W34SEL + case 0x2125: return mmio_w2125(data); //WOBJSEL + case 0x2126: return mmio_w2126(data); //WH0 + case 0x2127: return mmio_w2127(data); //WH1 + case 0x2128: return mmio_w2128(data); //WH2 + case 0x2129: return mmio_w2129(data); //WH3 + case 0x212a: return mmio_w212a(data); //WBGLOG + case 0x212b: return mmio_w212b(data); //WOBJLOG + case 0x212c: return mmio_w212c(data); //TM + case 0x212d: return mmio_w212d(data); //TS + case 0x212e: return mmio_w212e(data); //TMW + case 0x212f: return mmio_w212f(data); //TSW + case 0x2130: return mmio_w2130(data); //CGWSEL + case 0x2131: return mmio_w2131(data); //CGADDSUB + case 0x2132: return mmio_w2132(data); //COLDATA + case 0x2133: return mmio_w2133(data); //SETINI + } +} + +#endif diff --git a/snes/ppu/mmio/mmio.hpp b/snes/ppu/mmio/mmio.hpp new file mode 100755 index 00000000..0c105624 --- /dev/null +++ b/snes/ppu/mmio/mmio.hpp @@ -0,0 +1,162 @@ +public: + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + +private: + +struct { + uint8 ppu1_mdr; + uint8 ppu2_mdr; + + uint16 vram_readbuffer; + uint8 oam_latchdata; + uint8 cgram_latchdata; + uint8 bgofs_latchdata; + uint8 mode7_latchdata; + bool counters_latched; + bool latch_hcounter; + bool latch_vcounter; + + uint10 oam_iaddr; + uint9 cgram_iaddr; + + //$2100 INIDISP + bool display_disable; + uint4 display_brightness; + + //$2102 OAMADDL + //$2103 OAMADDH + uint10 oam_baseaddr; + uint10 oam_addr; + bool oam_priority; + + //$2105 BGMODE + bool bg3_priority; + uint8 bgmode; + + //$210d BG1HOFS + uint16 mode7_hoffset; + + //$210e BG1VOFS + uint16 mode7_voffset; + + //$2115 VMAIN + bool vram_incmode; + uint2 vram_mapping; + uint8 vram_incsize; + + //$2116 VMADDL + //$2117 VMADDH + uint16 vram_addr; + + //$211a M7SEL + uint2 mode7_repeat; + bool mode7_vflip; + bool mode7_hflip; + + //$211b M7A + uint16 m7a; + + //$211c M7B + uint16 m7b; + + //$211d M7C + uint16 m7c; + + //$211e M7D + uint16 m7d; + + //$211f M7X + uint16 m7x; + + //$2120 M7Y + uint16 m7y; + + //$2121 CGADD + uint9 cgram_addr; + + //$2133 SETINI + bool mode7_extbg; + bool pseudo_hires; + bool overscan; + bool interlace; + + //$213c OPHCT + uint16 hcounter; + + //$213d OPVCT + uint16 vcounter; +} regs; + +uint16 get_vram_address(); +uint8 vram_read(unsigned addr); +void vram_write(unsigned addr, uint8 data); + +void mmio_update_video_mode(); + +void mmio_w2100(uint8); //INIDISP +void mmio_w2101(uint8); //OBSEL +void mmio_w2102(uint8); //OAMADDL +void mmio_w2103(uint8); //OAMADDH +void mmio_w2104(uint8); //OAMDATA +void mmio_w2105(uint8); //BGMODE +void mmio_w2106(uint8); //MOSAIC +void mmio_w2107(uint8); //BG1SC +void mmio_w2108(uint8); //BG2SC +void mmio_w2109(uint8); //BG3SC +void mmio_w210a(uint8); //BG4SC +void mmio_w210b(uint8); //BG12NBA +void mmio_w210c(uint8); //BG34NBA +void mmio_w210d(uint8); //BG1HOFS +void mmio_w210e(uint8); //BG1VOFS +void mmio_w210f(uint8); //BG2HOFS +void mmio_w2110(uint8); //BG2VOFS +void mmio_w2111(uint8); //BG3HOFS +void mmio_w2112(uint8); //BG3VOFS +void mmio_w2113(uint8); //BG4HOFS +void mmio_w2114(uint8); //BG4VOFS +void mmio_w2115(uint8); //VMAIN +void mmio_w2116(uint8); //VMADDL +void mmio_w2117(uint8); //VMADDH +void mmio_w2118(uint8); //VMDATAL +void mmio_w2119(uint8); //VMDATAH +void mmio_w211a(uint8); //M7SEL +void mmio_w211b(uint8); //M7A +void mmio_w211c(uint8); //M7B +void mmio_w211d(uint8); //M7C +void mmio_w211e(uint8); //M7D +void mmio_w211f(uint8); //M7X +void mmio_w2120(uint8); //M7Y +void mmio_w2121(uint8); //CGADD +void mmio_w2122(uint8); //CGDATA +void mmio_w2123(uint8); //W12SEL +void mmio_w2124(uint8); //W34SEL +void mmio_w2125(uint8); //WOBJSEL +void mmio_w2126(uint8); //WH0 +void mmio_w2127(uint8); //WH1 +void mmio_w2128(uint8); //WH2 +void mmio_w2129(uint8); //WH3 +void mmio_w212a(uint8); //WBGLOG +void mmio_w212b(uint8); //WOBJLOG +void mmio_w212c(uint8); //TM +void mmio_w212d(uint8); //TS +void mmio_w212e(uint8); //TMW +void mmio_w212f(uint8); //TSW +void mmio_w2130(uint8); //CGWSEL +void mmio_w2131(uint8); //CGADDSUB +void mmio_w2132(uint8); //COLDATA +void mmio_w2133(uint8); //SETINI +uint8 mmio_r2134(); //MPYL +uint8 mmio_r2135(); //MPYM +uint8 mmio_r2136(); //MPYH +uint8 mmio_r2137(); //SLHV +uint8 mmio_r2138(); //OAMDATAREAD +uint8 mmio_r2139(); //VMDATALREAD +uint8 mmio_r213a(); //VMDATAHREAD +uint8 mmio_r213b(); //CGDATAREAD +uint8 mmio_r213c(); //OPHCT +uint8 mmio_r213d(); //OPVCT +uint8 mmio_r213e(); //STAT77 +uint8 mmio_r213f(); //STAT78 + +void mmio_reset(); diff --git a/snes/ppu/ppu.cpp b/snes/ppu/ppu.cpp new file mode 100755 index 00000000..ec213664 --- /dev/null +++ b/snes/ppu/ppu.cpp @@ -0,0 +1,164 @@ +#include + +#define PPU_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + PPUDebugger ppu; +#else + PPU ppu; +#endif + +#include "background/background.cpp" +#include "mmio/mmio.cpp" +#include "screen/screen.cpp" +#include "sprite/sprite.cpp" +#include "window/window.cpp" +#include "serialization.cpp" + +void PPU::step(unsigned clocks) { + clock += clocks; +} + +void PPU::synchronize_cpu() { + if(CPU::Threaded == true) { + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +} + +void PPU::Enter() { ppu.enter(); } + +void PPU::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + scanline(); + add_clocks(60); + bg1.begin(); + bg2.begin(); + bg3.begin(); + bg4.begin(); + + if(vcounter() <= 239) { + for(signed pixel = -7; pixel <= 255; pixel++) { + bg1.run(1); + bg2.run(1); + bg3.run(1); + bg4.run(1); + add_clocks(2); + + bg1.run(0); + bg2.run(0); + bg3.run(0); + bg4.run(0); + if(pixel >= 0) { + sprite.run(); + window.run(); + screen.run(); + } + add_clocks(2); + } + + add_clocks(22); + sprite.tilefetch(); + } else { + add_clocks(1052 + 22 + 136); + } + + add_clocks(lineclocks() - 60 - 1052 - 22 - 136); + } +} + +void PPU::add_clocks(unsigned clocks) { + clocks >>= 1; + while(clocks--) { + tick(2); + step(2); + synchronize_cpu(); + } +} + +void PPU::enable() { + function read = { &PPU::mmio_read, (PPU*)&ppu }; + function write = { &PPU::mmio_write, (PPU*)&ppu }; + + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write); +} + +void PPU::power() { + ppu1_version = config.ppu1.version; + ppu2_version = config.ppu2.version; + + for(auto &n : vram) n = random(0x00); + for(auto &n : oam) n = random(0x00); + for(auto &n : cgram) n = random(0x00); + + reset(); +} + +void PPU::reset() { + create(Enter, system.cpu_frequency()); + PPUcounter::reset(); + memset(surface, 0, 512 * 512 * sizeof(uint32)); + + mmio_reset(); + bg1.reset(); + bg2.reset(); + bg3.reset(); + bg4.reset(); + sprite.reset(); + window.reset(); + screen.reset(); + + frame(); +} + +void PPU::scanline() { + if(vcounter() == 0) { + frame(); + bg1.frame(); + bg2.frame(); + bg3.frame(); + bg4.frame(); + } + + bg1.scanline(); + bg2.scanline(); + bg3.scanline(); + bg4.scanline(); + sprite.scanline(); + window.scanline(); + screen.scanline(); +} + +void PPU::frame() { + system.frame(); + sprite.frame(); + + display.interlace = regs.interlace; + display.overscan = regs.overscan; +} + +PPU::PPU() : +bg1(*this, Background::ID::BG1), +bg2(*this, Background::ID::BG2), +bg3(*this, Background::ID::BG3), +bg4(*this, Background::ID::BG4), +sprite(*this), +window(*this), +screen(*this) { + surface = new uint32[512 * 512]; + output = surface + 16 * 512; +} + +PPU::~PPU() { + delete[] surface; +} + +} diff --git a/snes/ppu/ppu.hpp b/snes/ppu/ppu.hpp new file mode 100755 index 00000000..fdba113c --- /dev/null +++ b/snes/ppu/ppu.hpp @@ -0,0 +1,68 @@ +struct PPU : public Processor, public PPUcounter { + uint8 vram[64 * 1024]; + uint8 oam[544]; + uint8 cgram[512]; + + enum : bool { Threaded = true }; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_cpu(); + + void latch_counters(); + bool interlace() const; + bool overscan() const; + bool hires() const; + + void enter(); + void enable(); + void power(); + void reset(); + + void serialize(serializer&); + PPU(); + ~PPU(); + +private: + uint32 *surface; + uint32 *output; + + uint8 ppu1_version; + uint8 ppu2_version; + + struct { + bool interlace; + bool overscan; + } display; + + #include "background/background.hpp" + #include "mmio/mmio.hpp" + #include "screen/screen.hpp" + #include "sprite/sprite.hpp" + #include "window/window.hpp" + + Background bg1; + Background bg2; + Background bg3; + Background bg4; + Sprite sprite; + Window window; + Screen screen; + + static void Enter(); + void add_clocks(unsigned); + + void scanline(); + void frame(); + + friend class PPU::Background; + friend class PPU::Sprite; + friend class PPU::Window; + friend class PPU::Screen; + friend class Video; +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern PPUDebugger ppu; +#else + extern PPU ppu; +#endif diff --git a/snes/ppu/screen/screen.cpp b/snes/ppu/screen/screen.cpp new file mode 100755 index 00000000..64d2464d --- /dev/null +++ b/snes/ppu/screen/screen.cpp @@ -0,0 +1,210 @@ +#ifdef PPU_CPP + +void PPU::Screen::scanline() { + output = self.output + self.vcounter() * 1024; + if(self.display.interlace && self.field()) output += 512; +} + +void PPU::Screen::run() { + if(ppu.vcounter() == 0) return; + + uint32 color; + if(self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) { + color = get_pixel(0); + *output++ = color; + *output++ = color; + } else { + color = get_pixel(1); + *output++ = color; + color = get_pixel(0); + *output++ = color; + } +} + +uint32 PPU::Screen::get_pixel(bool swap) { + if(ppu.regs.overscan == false && ppu.vcounter() >= 225) return 0x0000; + + enum source_t { BG1, BG2, BG3, BG4, OAM, BACK }; + bool color_enable[] = { regs.bg1_color_enable, regs.bg2_color_enable, regs.bg3_color_enable, regs.bg4_color_enable, regs.oam_color_enable, regs.back_color_enable }; + + //=========== + //main screen + //=========== + + unsigned priority_main = 0; + unsigned color_main; + unsigned source_main; + + if(self.bg1.output.main.priority) { + priority_main = self.bg1.output.main.priority; + if(regs.direct_color && (self.regs.bgmode == 3 || self.regs.bgmode == 4 || self.regs.bgmode == 7)) { + color_main = get_direct_color(self.bg1.output.main.palette, self.bg1.output.main.tile); + } else { + color_main = get_color(self.bg1.output.main.palette); + } + source_main = BG1; + } + if(self.bg2.output.main.priority > priority_main) { + priority_main = self.bg2.output.main.priority; + color_main = get_color(self.bg2.output.main.palette); + source_main = BG2; + } + if(self.bg3.output.main.priority > priority_main) { + priority_main = self.bg3.output.main.priority; + color_main = get_color(self.bg3.output.main.palette); + source_main = BG3; + } + if(self.bg4.output.main.priority > priority_main) { + priority_main = self.bg4.output.main.priority; + color_main = get_color(self.bg4.output.main.palette); + source_main = BG4; + } + if(self.sprite.output.main.priority > priority_main) { + priority_main = self.sprite.output.main.priority; + color_main = get_color(self.sprite.output.main.palette); + source_main = OAM; + } + if(priority_main == 0) { + color_main = get_color(0); + source_main = BACK; + } + + //========== + //sub screen + //========== + + unsigned priority_sub = 0; + unsigned color_sub; + unsigned source_sub; + + if(self.bg1.output.sub.priority) { + priority_sub = self.bg1.output.sub.priority; + if(regs.direct_color && (self.regs.bgmode == 3 || self.regs.bgmode == 4 || self.regs.bgmode == 7)) { + color_sub = get_direct_color(self.bg1.output.sub.palette, self.bg1.output.sub.tile); + } else { + color_sub = get_color(self.bg1.output.sub.palette); + } + source_sub = BG1; + } + if(self.bg2.output.sub.priority > priority_sub) { + priority_sub = self.bg2.output.sub.priority; + color_sub = get_color(self.bg2.output.sub.palette); + source_sub = BG2; + } + if(self.bg3.output.sub.priority > priority_sub) { + priority_sub = self.bg3.output.sub.priority; + color_sub = get_color(self.bg3.output.sub.palette); + source_sub = BG3; + } + if(self.bg4.output.sub.priority > priority_sub) { + priority_sub = self.bg4.output.sub.priority; + color_sub = get_color(self.bg4.output.sub.palette); + source_sub = BG4; + } + if(self.sprite.output.sub.priority > priority_sub) { + priority_sub = self.sprite.output.sub.priority; + color_sub = get_color(self.sprite.output.sub.palette); + source_sub = OAM; + } + if(priority_sub == 0) { + if(self.regs.pseudo_hires == true || self.regs.bgmode == 5 || self.regs.bgmode == 6) { + color_sub = get_color(0); + } else { + color_sub = (regs.color_b << 10) + (regs.color_g << 5) + (regs.color_r << 0); + } + source_sub = BACK; + } + + if(swap == true) { + nall::swap(priority_main, priority_sub); + nall::swap(color_main, color_sub); + nall::swap(source_main, source_sub); + } + + uint16 output; + if(!regs.addsub_mode) { + source_sub = BACK; + color_sub = (regs.color_b << 10) + (regs.color_g << 5) + (regs.color_r << 0); + } + + if(self.window.output.main.color_enable == false) { + if(self.window.output.sub.color_enable == false) { + return 0x0000; + } + color_main = 0x0000; + } + + bool color_exempt = (source_main == OAM && self.sprite.output.main.palette < 192); + if(!color_exempt && color_enable[source_main] && self.window.output.sub.color_enable) { + bool halve = false; + if(regs.color_halve && self.window.output.main.color_enable) { + if(!regs.addsub_mode || source_sub != BACK) halve = true; + } + output = addsub(color_main, color_sub, halve); + } else { + output = color_main; + } + + //======== + //lighting + //======== + + if(self.regs.display_disable) return 0; + return (self.regs.display_brightness << 15) | output; +} + +uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) { + if(!regs.color_mode) { + if(!halve) { + unsigned sum = x + y; + unsigned carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; + return (sum - carry) | (carry - (carry >> 5)); + } else { + return (x + y - ((x ^ y) & 0x0421)) >> 1; + } + } else { + unsigned diff = x - y + 0x8420; + unsigned borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420; + if(!halve) { + return (diff - borrow) & (borrow - (borrow >> 5)); + } else { + return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1; + } + } +} + +uint16 PPU::Screen::get_color(unsigned palette) { + palette <<= 1; + self.regs.cgram_iaddr = palette; + return ppu.cgram[palette + 0] + (ppu.cgram[palette + 1] << 8); +} + +uint16 PPU::Screen::get_direct_color(unsigned palette, unsigned tile) { + //palette = -------- BBGGGRRR + //tile = ---bgr-- -------- + //output = 0BBb00GG Gg0RRRr0 + return ((palette << 7) & 0x6000) + ((tile >> 0) & 0x1000) + + ((palette << 4) & 0x0380) + ((tile >> 5) & 0x0040) + + ((palette << 2) & 0x001c) + ((tile >> 9) & 0x0002); +} + +void PPU::Screen::reset() { + regs.addsub_mode = random(false); + regs.direct_color = random(false); + regs.color_mode = random(false); + regs.color_halve = random(false); + regs.bg1_color_enable = random(false); + regs.bg2_color_enable = random(false); + regs.bg3_color_enable = random(false); + regs.bg4_color_enable = random(false); + regs.oam_color_enable = random(false); + regs.back_color_enable = random(false); + regs.color_r = random(0); + regs.color_g = random(0); + regs.color_b = random(0); +} + +PPU::Screen::Screen(PPU &self) : self(self) { +} + +#endif diff --git a/snes/ppu/screen/screen.hpp b/snes/ppu/screen/screen.hpp new file mode 100755 index 00000000..15502335 --- /dev/null +++ b/snes/ppu/screen/screen.hpp @@ -0,0 +1,36 @@ +class Screen { + uint32 *output; + + struct Regs { + bool addsub_mode; + bool direct_color; + + bool color_mode; + bool color_halve; + bool bg1_color_enable; + bool bg2_color_enable; + bool bg3_color_enable; + bool bg4_color_enable; + bool oam_color_enable; + bool back_color_enable; + + uint5 color_b; + uint5 color_g; + uint5 color_r; + } regs; + + void scanline(); + void run(); + void reset(); + + uint32 get_pixel(bool swap); + uint16 addsub(unsigned x, unsigned y, bool halve); + uint16 get_color(unsigned palette); + uint16 get_direct_color(unsigned palette, unsigned tile); + + void serialize(serializer&); + Screen(PPU &self); + + PPU &self; + friend class PPU; +}; diff --git a/snes/ppu/serialization.cpp b/snes/ppu/serialization.cpp new file mode 100755 index 00000000..edf90f13 --- /dev/null +++ b/snes/ppu/serialization.cpp @@ -0,0 +1,284 @@ +#ifdef PPU_CPP + +void PPUcounter::serialize(serializer &s) { + s.integer(status.interlace); + s.integer(status.field); + s.integer(status.vcounter); + s.integer(status.hcounter); + + s.array(history.field); + s.array(history.vcounter); + s.array(history.hcounter); + s.integer(history.index); +} + +void PPU::serialize(serializer &s) { + Processor::serialize(s); + PPUcounter::serialize(s); + + s.array(vram); + s.array(oam); + s.array(cgram); + + s.integer(ppu1_version); + s.integer(ppu2_version); + + s.integer(display.interlace); + s.integer(display.overscan); + + s.integer(regs.ppu1_mdr); + s.integer(regs.ppu2_mdr); + + s.integer(regs.vram_readbuffer); + s.integer(regs.oam_latchdata); + s.integer(regs.cgram_latchdata); + s.integer(regs.bgofs_latchdata); + s.integer(regs.mode7_latchdata); + s.integer(regs.counters_latched); + s.integer(regs.latch_hcounter); + s.integer(regs.latch_vcounter); + + s.integer(regs.oam_iaddr); + s.integer(regs.cgram_iaddr); + + s.integer(regs.display_disable); + s.integer(regs.display_brightness); + + s.integer(regs.oam_baseaddr); + s.integer(regs.oam_addr); + s.integer(regs.oam_priority); + + s.integer(regs.bg3_priority); + s.integer(regs.bgmode); + + s.integer(regs.mode7_hoffset); + s.integer(regs.mode7_voffset); + + s.integer(regs.vram_incmode); + s.integer(regs.vram_mapping); + s.integer(regs.vram_incsize); + + s.integer(regs.vram_addr); + + s.integer(regs.mode7_repeat); + s.integer(regs.mode7_vflip); + s.integer(regs.mode7_hflip); + + s.integer(regs.m7a); + s.integer(regs.m7b); + s.integer(regs.m7c); + s.integer(regs.m7d); + s.integer(regs.m7x); + s.integer(regs.m7y); + + s.integer(regs.cgram_addr); + + s.integer(regs.mode7_extbg); + s.integer(regs.pseudo_hires); + s.integer(regs.overscan); + s.integer(regs.interlace); + + s.integer(regs.hcounter); + s.integer(regs.vcounter); + + bg1.serialize(s); + bg2.serialize(s); + bg3.serialize(s); + bg4.serialize(s); + sprite.serialize(s); + window.serialize(s); + screen.serialize(s); +} + +void PPU::Background::serialize(serializer &s) { + s.integer(id); + + s.integer(regs.tiledata_addr); + s.integer(regs.screen_addr); + s.integer(regs.screen_size); + s.integer(regs.mosaic); + s.integer(regs.tile_size); + + s.integer(regs.mode); + s.integer(regs.priority0); + s.integer(regs.priority1); + + s.integer(regs.main_enable); + s.integer(regs.sub_enable); + + s.integer(regs.hoffset); + s.integer(regs.voffset); + + s.integer(cache.hoffset); + s.integer(cache.voffset); + + s.integer(output.main.priority); + s.integer(output.main.palette); + s.integer(output.main.tile); + + s.integer(output.sub.priority); + s.integer(output.sub.palette); + s.integer(output.sub.tile); + + s.integer(x); + s.integer(y); + + s.integer(mosaic.priority); + s.integer(mosaic.palette); + s.integer(mosaic.tile); + + s.integer(mosaic.vcounter); + s.integer(mosaic.voffset); + s.integer(mosaic.hcounter); + s.integer(mosaic.hoffset); + + s.integer(tile_counter); + s.integer(tile); + s.integer(priority); + s.integer(palette_number); + s.integer(palette_index); + s.array(data); +} + +void PPU::Sprite::serialize(serializer &s) { + for(unsigned i = 0; i < 128; i++) { + s.integer(list[i].x); + s.integer(list[i].y); + s.integer(list[i].character); + s.integer(list[i].nameselect); + s.integer(list[i].vflip); + s.integer(list[i].hflip); + s.integer(list[i].priority); + s.integer(list[i].palette); + s.integer(list[i].size); + } + + s.integer(t.x); + s.integer(t.y); + + s.integer(t.item_count); + s.integer(t.tile_count); + + s.integer(t.active); + for(unsigned n = 0; n < 2; n++) { + s.array(t.item[n]); + for(unsigned i = 0; i < 34; i++) { + s.integer(t.tile[n][i].x); + s.integer(t.tile[n][i].priority); + s.integer(t.tile[n][i].palette); + s.integer(t.tile[n][i].hflip); + s.integer(t.tile[n][i].d0); + s.integer(t.tile[n][i].d1); + s.integer(t.tile[n][i].d2); + s.integer(t.tile[n][i].d3); + } + } + + s.integer(regs.main_enable); + s.integer(regs.sub_enable); + s.integer(regs.interlace); + + s.integer(regs.base_size); + s.integer(regs.nameselect); + s.integer(regs.tiledata_addr); + s.integer(regs.first_sprite); + + s.integer(regs.priority0); + s.integer(regs.priority1); + s.integer(regs.priority2); + s.integer(regs.priority3); + + s.integer(regs.time_over); + s.integer(regs.range_over); + + s.integer(output.main.priority); + s.integer(output.main.palette); + + s.integer(output.sub.priority); + s.integer(output.sub.palette); +} + +void PPU::Window::serialize(serializer &s) { + s.integer(regs.bg1_one_enable); + s.integer(regs.bg1_one_invert); + s.integer(regs.bg1_two_enable); + s.integer(regs.bg1_two_invert); + + s.integer(regs.bg2_one_enable); + s.integer(regs.bg2_one_invert); + s.integer(regs.bg2_two_enable); + s.integer(regs.bg2_two_invert); + + s.integer(regs.bg3_one_enable); + s.integer(regs.bg3_one_invert); + s.integer(regs.bg3_two_enable); + s.integer(regs.bg3_two_invert); + + s.integer(regs.bg4_one_enable); + s.integer(regs.bg4_one_invert); + s.integer(regs.bg4_two_enable); + s.integer(regs.bg4_two_invert); + + s.integer(regs.oam_one_enable); + s.integer(regs.oam_one_invert); + s.integer(regs.oam_two_enable); + s.integer(regs.oam_two_invert); + + s.integer(regs.col_one_enable); + s.integer(regs.col_one_invert); + s.integer(regs.col_two_enable); + s.integer(regs.col_two_invert); + + s.integer(regs.one_left); + s.integer(regs.one_right); + s.integer(regs.two_left); + s.integer(regs.two_right); + + s.integer(regs.bg1_mask); + s.integer(regs.bg2_mask); + s.integer(regs.bg3_mask); + s.integer(regs.bg4_mask); + s.integer(regs.oam_mask); + s.integer(regs.col_mask); + + s.integer(regs.bg1_main_enable); + s.integer(regs.bg1_sub_enable); + s.integer(regs.bg2_main_enable); + s.integer(regs.bg2_sub_enable); + s.integer(regs.bg3_main_enable); + s.integer(regs.bg3_sub_enable); + s.integer(regs.bg4_main_enable); + s.integer(regs.bg4_sub_enable); + s.integer(regs.oam_main_enable); + s.integer(regs.oam_sub_enable); + + s.integer(regs.col_main_mask); + s.integer(regs.col_sub_mask); + + s.integer(output.main.color_enable); + s.integer(output.sub.color_enable); + + s.integer(x); + s.integer(one); + s.integer(two); +} + +void PPU::Screen::serialize(serializer &s) { + s.integer(regs.addsub_mode); + s.integer(regs.direct_color); + + s.integer(regs.color_mode); + s.integer(regs.color_halve); + s.integer(regs.bg1_color_enable); + s.integer(regs.bg2_color_enable); + s.integer(regs.bg3_color_enable); + s.integer(regs.bg4_color_enable); + s.integer(regs.oam_color_enable); + s.integer(regs.back_color_enable); + + s.integer(regs.color_b); + s.integer(regs.color_g); + s.integer(regs.color_r); +} + +#endif diff --git a/snes/ppu/sprite/list.cpp b/snes/ppu/sprite/list.cpp new file mode 100755 index 00000000..dda35883 --- /dev/null +++ b/snes/ppu/sprite/list.cpp @@ -0,0 +1,60 @@ +#ifdef PPU_CPP + +void PPU::Sprite::update(unsigned addr, uint8 data) { + ppu.oam[addr] = data; + + if(addr < 0x0200) { + unsigned n = addr >> 2; + addr &= 3; + if(addr == 0) { + list[n].x = (list[n].x & 0x100) | data; + } else if(addr == 1) { + list[n].y = data; + } else if(addr == 2) { + list[n].character = data; + } else { //(addr == 3) + list[n].vflip = data & 0x80; + list[n].hflip = data & 0x40; + list[n].priority = (data >> 4) & 3; + list[n].palette = (data >> 1) & 7; + list[n].nameselect = data & 1; + } + } else { + unsigned n = (addr & 0x1f) << 2; + list[n + 0].x = ((data & 0x01) << 8) | (list[n + 0].x & 0xff); + list[n + 0].size = data & 0x02; + list[n + 1].x = ((data & 0x04) << 6) | (list[n + 1].x & 0xff); + list[n + 1].size = data & 0x08; + list[n + 2].x = ((data & 0x10) << 4) | (list[n + 2].x & 0xff); + list[n + 2].size = data & 0x20; + list[n + 3].x = ((data & 0x40) << 2) | (list[n + 3].x & 0xff); + list[n + 3].size = data & 0x80; + } +} + +void PPU::Sprite::synchronize() { + for(unsigned n = 0; n < 544; n++) update(n, ppu.oam[n]); +} + +unsigned PPU::Sprite::SpriteItem::width() const { + if(size == 0) { + static unsigned width[] = { 8, 8, 8, 16, 16, 32, 16, 16 }; + return width[ppu.sprite.regs.base_size]; + } else { + static unsigned width[] = { 16, 32, 64, 32, 64, 64, 32, 32 }; + return width[ppu.sprite.regs.base_size]; + } +} + +unsigned PPU::Sprite::SpriteItem::height() const { + if(size == 0) { + if(ppu.sprite.regs.interlace && ppu.sprite.regs.base_size >= 6) return 16; + static unsigned height[] = { 8, 8, 8, 16, 16, 32, 32, 32 }; + return height[ppu.sprite.regs.base_size]; + } else { + static unsigned height[] = { 16, 32, 64, 32, 64, 64, 64, 32 }; + return height[ppu.sprite.regs.base_size]; + } +} + +#endif diff --git a/snes/ppu/sprite/sprite.cpp b/snes/ppu/sprite/sprite.cpp new file mode 100755 index 00000000..5bc60b3e --- /dev/null +++ b/snes/ppu/sprite/sprite.cpp @@ -0,0 +1,223 @@ +#ifdef PPU_CPP + +#include "list.cpp" + +void PPU::Sprite::address_reset() { + self.regs.oam_addr = self.regs.oam_baseaddr; + set_first_sprite(); +} + +void PPU::Sprite::set_first_sprite() { + regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127); +} + +void PPU::Sprite::frame() { + regs.time_over = false; + regs.range_over = false; +} + +void PPU::Sprite::scanline() { + t.x = 0; + t.y = self.vcounter(); + + t.item_count = 0; + t.tile_count = 0; + + t.active = !t.active; + auto oam_item = t.item[t.active]; + auto oam_tile = t.tile[t.active]; + + if(t.y == (!self.regs.overscan ? 225 : 240) && self.regs.display_disable == false) address_reset(); + if(t.y >= (!self.regs.overscan ? 224 : 239)) return; + + memset(oam_item, 0xff, 32); //default to invalid + for(unsigned i = 0; i < 34; i++) oam_tile[i].x = 0xffff; //default to invalid + + for(unsigned i = 0; i < 128; i++) { + unsigned sprite = (regs.first_sprite + i) & 127; + if(on_scanline(list[sprite]) == false) continue; + if(t.item_count++ >= 32) break; + oam_item[t.item_count - 1] = sprite; + } + + if(t.item_count > 0 && oam_item[t.item_count - 1] != 0xff) { + ppu.regs.oam_iaddr = 0x0200 + (oam_item[t.item_count - 1] >> 2); + } +} + +bool PPU::Sprite::on_scanline(SpriteItem &sprite) { + if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false; + signed height = (regs.interlace == false ? sprite.height() : (sprite.height() >> 1)); + if(t.y >= sprite.y && t.y < (sprite.y + height)) return true; + if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true; + return false; +} + +void PPU::Sprite::run() { + output.main.priority = 0; + output.sub.priority = 0; + + auto oam_tile = t.tile[!t.active]; + unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 }; + unsigned x = t.x++; + + for(unsigned n = 0; n < 34; n++) { + auto tile = oam_tile[n]; + if(tile.x == 0xffff) break; + + int px = x - sclip<9>(tile.x); + if(px & ~7) continue; + + unsigned mask = 0x80 >> (tile.hflip == false ? px : 7 - px); + unsigned color; + color = ((bool)(tile.d0 & mask)) << 0; + color |= ((bool)(tile.d1 & mask)) << 1; + color |= ((bool)(tile.d2 & mask)) << 2; + color |= ((bool)(tile.d3 & mask)) << 3; + + if(color) { + if(regs.main_enable) { + output.main.palette = tile.palette + color; + output.main.priority = priority_table[tile.priority]; + } + + if(regs.sub_enable) { + output.sub.palette = tile.palette + color; + output.sub.priority = priority_table[tile.priority]; + } + } + } +} + +void PPU::Sprite::tilefetch() { + auto oam_item = t.item[t.active]; + auto oam_tile = t.tile[t.active]; + + for(signed i = 31; i >= 0; i--) { + if(oam_item[i] == 0xff) continue; + auto sprite = list[oam_item[i]]; + + unsigned tile_width = sprite.width() >> 3; + signed x = sprite.x; + signed y = (t.y - sprite.y) & 0xff; + if(regs.interlace) y <<= 1; + + if(sprite.vflip) { + if(sprite.width() == sprite.height()) { + y = (sprite.height() - 1) - y; + } else if(y < sprite.width()) { + y = (sprite.width() - 1) - y; + } else { + y = sprite.width() + ((sprite.width() - 1) - (y - sprite.width())); + } + } + + if(regs.interlace) { + y = (sprite.vflip == false ? y + self.field() : y - self.field()); + } + + x &= 511; + y &= 255; + + uint16 tiledata_addr = regs.tiledata_addr; + uint16 chrx = (sprite.character >> 0) & 15; + uint16 chry = (sprite.character >> 4) & 15; + if(sprite.nameselect) { + tiledata_addr += (256 * 32) + (regs.nameselect << 13); + } + chry += (y >> 3); + chry &= 15; + chry <<= 4; + + for(unsigned tx = 0; tx < tile_width; tx++) { + unsigned sx = (x + (tx << 3)) & 511; + if(x != 256 && sx >= 256 && (sx + 7) < 512) continue; + if(t.tile_count++ >= 34) break; + + unsigned n = t.tile_count - 1; + oam_tile[n].x = sx; + oam_tile[n].priority = sprite.priority; + oam_tile[n].palette = 128 + (sprite.palette << 4); + oam_tile[n].hflip = sprite.hflip; + + unsigned mx = (sprite.hflip == false) ? tx : ((tile_width - 1) - tx); + unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5); + uint16 addr = (pos & 0xffe0) + ((y & 7) * 2); + + oam_tile[n].d0 = ppu.vram[addr + 0]; + oam_tile[n].d1 = ppu.vram[addr + 1]; + self.add_clocks(2); + + oam_tile[n].d2 = ppu.vram[addr + 16]; + oam_tile[n].d3 = ppu.vram[addr + 17]; + self.add_clocks(2); + } + } + + if(t.tile_count < 34) self.add_clocks((34 - t.tile_count) * 4); + regs.time_over |= (t.tile_count > 34); + regs.range_over |= (t.item_count > 32); +} + +void PPU::Sprite::reset() { + for(unsigned i = 0; i < 128; i++) { + list[i].x = 0; + list[i].y = 0; + list[i].character = 0; + list[i].nameselect = 0; + list[i].vflip = 0; + list[i].hflip = 0; + list[i].priority = 0; + list[i].palette = 0; + list[i].size = 0; + } + synchronize(); + + t.x = 0; + t.y = 0; + + t.item_count = 0; + t.tile_count = 0; + + t.active = 0; + for(unsigned n = 0; n < 2; n++) { + memset(t.item[n], 0, 32); + for(unsigned i = 0; i < 34; i++) { + t.tile[n][i].x = 0; + t.tile[n][i].priority = 0; + t.tile[n][i].palette = 0; + t.tile[n][i].hflip = 0; + t.tile[n][i].d0 = 0; + t.tile[n][i].d1 = 0; + t.tile[n][i].d2 = 0; + t.tile[n][i].d3 = 0; + } + } + + regs.main_enable = random(false); + regs.sub_enable = random(false); + regs.interlace = random(false); + + regs.base_size = random(0); + regs.nameselect = random(0); + regs.tiledata_addr = random(0x0000); + regs.first_sprite = 0; + + regs.priority0 = 0; + regs.priority1 = 0; + regs.priority2 = 0; + regs.priority3 = 0; + + regs.time_over = false; + regs.range_over = false; + + output.main.palette = 0; + output.main.priority = 0; + output.sub.palette = 0; + output.sub.priority = 0; +} + +PPU::Sprite::Sprite(PPU &self) : self(self) { +} + +#endif diff --git a/snes/ppu/sprite/sprite.hpp b/snes/ppu/sprite/sprite.hpp new file mode 100755 index 00000000..641ac13c --- /dev/null +++ b/snes/ppu/sprite/sprite.hpp @@ -0,0 +1,82 @@ +class Sprite { + struct SpriteItem { + uint16 x; + uint16 y; + uint8 character; + bool nameselect; + bool vflip; + bool hflip; + uint8 priority; + uint8 palette; + bool size; + unsigned width() const; + unsigned height() const; + } list[128]; + + struct TileItem { + uint16 x; + uint16 priority; + uint16 palette; + bool hflip; + uint8 d0, d1, d2, d3; + }; + + struct State { + unsigned x; + unsigned y; + + unsigned item_count; + unsigned tile_count; + + bool active; + uint8 item[2][32]; + TileItem tile[2][34]; + } t; + + struct Regs { + bool main_enable; + bool sub_enable; + bool interlace; + + uint3 base_size; + uint2 nameselect; + uint16 tiledata_addr; + uint8 first_sprite; + + unsigned priority0; + unsigned priority1; + unsigned priority2; + unsigned priority3; + + bool time_over; + bool range_over; + } regs; + + struct Output { + struct Pixel { + unsigned priority; //0 = none (transparent) + uint8 palette; + } main, sub; + } output; + + //list.cpp + void update(unsigned addr, uint8 data); + void synchronize(); + + //sprite.cpp + void address_reset(); + void set_first_sprite(); + void frame(); + void scanline(); + void run(); + void tilefetch(); + void reset(); + + bool on_scanline(SpriteItem&); + + void serialize(serializer&); + Sprite(PPU &self); + + PPU &self; + friend class PPU; +}; diff --git a/snes/ppu/window/window.cpp b/snes/ppu/window/window.cpp new file mode 100755 index 00000000..dec05876 --- /dev/null +++ b/snes/ppu/window/window.cpp @@ -0,0 +1,169 @@ +#ifdef PPU_CPP + +void PPU::Window::scanline() { + x = 0; +} + +void PPU::Window::run() { + bool main, sub; + one = (x >= regs.one_left && x <= regs.one_right); + two = (x >= regs.two_left && x <= regs.two_right); + x++; + + test( + main, sub, + regs.bg1_one_enable, regs.bg1_one_invert, + regs.bg1_two_enable, regs.bg1_two_invert, + regs.bg1_mask, regs.bg1_main_enable, regs.bg1_sub_enable + ); + if(main) self.bg1.output.main.priority = 0; + if(sub) self.bg1.output.sub.priority = 0; + + test( + main, sub, + regs.bg2_one_enable, regs.bg2_one_invert, + regs.bg2_two_enable, regs.bg2_two_invert, + regs.bg2_mask, regs.bg2_main_enable, regs.bg2_sub_enable + ); + if(main) self.bg2.output.main.priority = 0; + if(sub) self.bg2.output.sub.priority = 0; + + test( + main, sub, + regs.bg3_one_enable, regs.bg3_one_invert, + regs.bg3_two_enable, regs.bg3_two_invert, + regs.bg3_mask, regs.bg3_main_enable, regs.bg3_sub_enable + ); + if(main) self.bg3.output.main.priority = 0; + if(sub) self.bg3.output.sub.priority = 0; + + test( + main, sub, + regs.bg4_one_enable, regs.bg4_one_invert, + regs.bg4_two_enable, regs.bg4_two_invert, + regs.bg4_mask, regs.bg4_main_enable, regs.bg4_sub_enable + ); + if(main) self.bg4.output.main.priority = 0; + if(sub) self.bg4.output.sub.priority = 0; + + test( + main, sub, + regs.oam_one_enable, regs.oam_one_invert, + regs.oam_two_enable, regs.oam_two_invert, + regs.oam_mask, regs.oam_main_enable, regs.oam_sub_enable + ); + if(main) self.sprite.output.main.priority = 0; + if(sub) self.sprite.output.sub.priority = 0; + + test( + main, sub, + regs.col_one_enable, regs.col_one_invert, + regs.col_two_enable, regs.col_two_invert, + regs.col_mask, true, true + ); + + switch(regs.col_main_mask) { + case 0: main = true; break; + case 1: break; + case 2: main = !main; break; + case 3: main = false; break; + } + + switch(regs.col_sub_mask) { + case 0: sub = true; break; + case 1: break; + case 2: sub = !sub; break; + case 3: sub = false; break; + } + + output.main.color_enable = main; + output.sub.color_enable = sub; +} + +void PPU::Window::test( + bool &main, bool &sub, + bool one_enable, bool one_invert, + bool two_enable, bool two_invert, + uint8 mask, bool main_enable, bool sub_enable +) { + bool one = Window::one ^ one_invert; + bool two = Window::two ^ two_invert; + bool output; + + if(one_enable == false && two_enable == false) { + output = false; + } else if(one_enable == true && two_enable == false) { + output = one; + } else if(one_enable == false && two_enable == true) { + output = two; + } else switch(mask) { + case 0: output = (one | two) == 1; break; + case 1: output = (one & two) == 1; break; + case 2: output = (one ^ two) == 1; break; + case 3: output = (one ^ two) == 0; break; + } + + main = main_enable ? output : false; + sub = sub_enable ? output : false; +} + +void PPU::Window::reset() { + regs.bg1_one_enable = random(false); + regs.bg1_one_invert = random(false); + regs.bg1_two_enable = random(false); + regs.bg1_two_invert = random(false); + regs.bg2_one_enable = random(false); + regs.bg2_one_invert = random(false); + regs.bg2_two_enable = random(false); + regs.bg2_two_invert = random(false); + regs.bg3_one_enable = random(false); + regs.bg3_one_invert = random(false); + regs.bg3_two_enable = random(false); + regs.bg3_two_invert = random(false); + regs.bg4_one_enable = random(false); + regs.bg4_one_invert = random(false); + regs.bg4_two_enable = random(false); + regs.bg4_two_invert = random(false); + regs.oam_one_enable = random(false); + regs.oam_one_invert = random(false); + regs.oam_two_enable = random(false); + regs.oam_two_invert = random(false); + regs.col_one_enable = random(false); + regs.col_one_invert = random(false); + regs.col_two_enable = random(false); + regs.col_two_invert = random(false); + regs.one_left = random(0x00); + regs.one_right = random(0x00); + regs.two_left = random(0x00); + regs.two_right = random(0x00); + regs.bg1_mask = random(0); + regs.bg2_mask = random(0); + regs.bg3_mask = random(0); + regs.bg4_mask = random(0); + regs.oam_mask = random(0); + regs.col_mask = random(0); + regs.bg1_main_enable = random(false); + regs.bg1_sub_enable = random(false); + regs.bg2_main_enable = random(false); + regs.bg2_sub_enable = random(false); + regs.bg3_main_enable = random(false); + regs.bg3_sub_enable = random(false); + regs.bg4_main_enable = random(false); + regs.bg4_sub_enable = random(false); + regs.oam_main_enable = random(false); + regs.oam_sub_enable = random(false); + regs.col_main_mask = random(0); + regs.col_sub_mask = random(0); + + output.main.color_enable = 0; + output.sub.color_enable = 0; + + x = 0; + one = 0; + two = 0; +} + +PPU::Window::Window(PPU &self) : self(self) { +} + +#endif diff --git a/snes/ppu/window/window.hpp b/snes/ppu/window/window.hpp new file mode 100755 index 00000000..a4bad10e --- /dev/null +++ b/snes/ppu/window/window.hpp @@ -0,0 +1,88 @@ +class Window { + struct { + bool bg1_one_enable; + bool bg1_one_invert; + bool bg1_two_enable; + bool bg1_two_invert; + + bool bg2_one_enable; + bool bg2_one_invert; + bool bg2_two_enable; + bool bg2_two_invert; + + bool bg3_one_enable; + bool bg3_one_invert; + bool bg3_two_enable; + bool bg3_two_invert; + + bool bg4_one_enable; + bool bg4_one_invert; + bool bg4_two_enable; + bool bg4_two_invert; + + bool oam_one_enable; + bool oam_one_invert; + bool oam_two_enable; + bool oam_two_invert; + + bool col_one_enable; + bool col_one_invert; + bool col_two_enable; + bool col_two_invert; + + uint8 one_left; + uint8 one_right; + uint8 two_left; + uint8 two_right; + + uint2 bg1_mask; + uint2 bg2_mask; + uint2 bg3_mask; + uint2 bg4_mask; + uint2 oam_mask; + uint2 col_mask; + + bool bg1_main_enable; + bool bg1_sub_enable; + bool bg2_main_enable; + bool bg2_sub_enable; + bool bg3_main_enable; + bool bg3_sub_enable; + bool bg4_main_enable; + bool bg4_sub_enable; + bool oam_main_enable; + bool oam_sub_enable; + + uint2 col_main_mask; + uint2 col_sub_mask; + } regs; + + struct Output { + struct Pixel { + bool color_enable; + } main, sub; + } output; + + struct { + unsigned x; + bool one; + bool two; + }; + + void scanline(); + void run(); + void reset(); + + void test( + bool &main, bool &sub, + bool one_enable, bool one_invert, + bool two_enable, bool two_invert, + uint8 mask, bool main_enable, bool sub_enable + ); + + void serialize(serializer&); + Window(PPU &self); + + PPU &self; + friend class PPU; +}; diff --git a/snes/profile-accuracy.hpp b/snes/profile-accuracy.hpp new file mode 100755 index 00000000..7b6dded8 --- /dev/null +++ b/snes/profile-accuracy.hpp @@ -0,0 +1,8 @@ +namespace Info { + static const char Profile[] = "Accuracy"; +} + +#include +#include +#include +#include diff --git a/snes/profile-compatibility.hpp b/snes/profile-compatibility.hpp new file mode 100755 index 00000000..bbf3582d --- /dev/null +++ b/snes/profile-compatibility.hpp @@ -0,0 +1,8 @@ +namespace Info { + static const char Profile[] = "Compatibility"; +} + +#include +#include +#include +#include diff --git a/snes/profile-performance.hpp b/snes/profile-performance.hpp new file mode 100755 index 00000000..1d379fdc --- /dev/null +++ b/snes/profile-performance.hpp @@ -0,0 +1,12 @@ +namespace Info { + static const char Profile[] = "Performance"; +} + +#if defined(DEBUGGER) + #error "bsnes: debugger not supported with performance profile." +#endif + +#include +#include +#include +#include diff --git a/snes/random/random.cpp b/snes/random/random.cpp new file mode 100755 index 00000000..a92a980a --- /dev/null +++ b/snes/random/random.cpp @@ -0,0 +1,18 @@ +Random random; + +void Random::seed(unsigned seed_iter) { + iter = seed_iter; +} + +unsigned Random::operator()(unsigned result) { + if(config.random == false) return result; + return iter = (iter >> 1) ^ (((iter & 1) - 1) & 0xedb88320); +} + +void Random::serialize(serializer &s) { + s.integer(iter); +} + +Random::Random() { + iter = 0; +} diff --git a/snes/random/random.hpp b/snes/random/random.hpp new file mode 100755 index 00000000..927d7172 --- /dev/null +++ b/snes/random/random.hpp @@ -0,0 +1,11 @@ +struct Random { + void seed(unsigned seed); + unsigned operator()(unsigned result = 0); + void serialize(serializer&); + Random(); + +private: + unsigned iter; +}; + +extern Random random; diff --git a/snes/scheduler/scheduler.cpp b/snes/scheduler/scheduler.cpp new file mode 100755 index 00000000..e7549501 --- /dev/null +++ b/snes/scheduler/scheduler.cpp @@ -0,0 +1,28 @@ +#ifdef SYSTEM_CPP + +Scheduler scheduler; + +void Scheduler::enter() { + host_thread = co_active(); + co_switch(thread); +} + +void Scheduler::exit(ExitReason reason) { + exit_reason = reason; + thread = co_active(); + co_switch(host_thread); +} + +void Scheduler::init() { + host_thread = co_active(); + thread = cpu.thread; + sync = SynchronizeMode::None; +} + +Scheduler::Scheduler() { + host_thread = 0; + thread = 0; + exit_reason = ExitReason::UnknownEvent; +} + +#endif diff --git a/snes/scheduler/scheduler.hpp b/snes/scheduler/scheduler.hpp new file mode 100755 index 00000000..335d8e9c --- /dev/null +++ b/snes/scheduler/scheduler.hpp @@ -0,0 +1,16 @@ +struct Scheduler : property { + enum class SynchronizeMode : unsigned { None, CPU, All } sync; + enum class ExitReason : unsigned { UnknownEvent, FrameEvent, SynchronizeEvent, DebuggerEvent }; + readonly exit_reason; + + cothread_t host_thread; //program thread (used to exit emulation) + cothread_t thread; //active emulation thread (used to enter emulation) + + void enter(); + void exit(ExitReason); + + void init(); + Scheduler(); +}; + +extern Scheduler scheduler; diff --git a/snes/smp/core/algorithms.cpp b/snes/smp/core/algorithms.cpp new file mode 100755 index 00000000..30a21076 --- /dev/null +++ b/snes/smp/core/algorithms.cpp @@ -0,0 +1,126 @@ +#ifdef SMPCORE_CPP + +uint8 SMPcore::op_adc(uint8 x, uint8 y) { + int r = x + y + regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = ~(x ^ y) & (x ^ r) & 0x80; + regs.p.h = (x ^ y ^ r) & 0x10; + regs.p.z = (uint8)r == 0; + regs.p.c = r > 0xff; + return r; +} + +uint16 SMPcore::op_addw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 0; + r = op_adc(x, y); + r |= op_adc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMPcore::op_and(uint8 x, uint8 y) { + x &= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMPcore::op_cmp(uint8 x, uint8 y) { + int r = x - y; + regs.p.n = r & 0x80; + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint16 SMPcore::op_cmpw(uint16 x, uint16 y) { + int r = x - y; + regs.p.n = r & 0x8000; + regs.p.z = (uint16)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint8 SMPcore::op_eor(uint8 x, uint8 y) { + x ^= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMPcore::op_or(uint8 x, uint8 y) { + x |= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMPcore::op_sbc(uint8 x, uint8 y) { + int r = x - y - !regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = (x ^ y) & (x ^ r) & 0x80; + regs.p.h = !((x ^ y ^ r) & 0x10); + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return r; +} + +uint16 SMPcore::op_subw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 1; + r = op_sbc(x, y); + r |= op_sbc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMPcore::op_inc(uint8 x) { + x++; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMPcore::op_dec(uint8 x) { + x--; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMPcore::op_asl(uint8 x) { + regs.p.c = x & 0x80; + x <<= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMPcore::op_lsr(uint8 x) { + regs.p.c = x & 0x01; + x >>= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMPcore::op_rol(uint8 x) { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = x & 0x80; + x = (x << 1) | carry; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMPcore::op_ror(uint8 x) { + unsigned carry = (unsigned)regs.p.c << 7; + regs.p.c = x & 0x01; + x = carry | (x >> 1); + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +#endif diff --git a/snes/smp/core/core.cpp b/snes/smp/core/core.cpp new file mode 100755 index 00000000..51fa453e --- /dev/null +++ b/snes/smp/core/core.cpp @@ -0,0 +1,31 @@ +#include + +#define SMPCORE_CPP +namespace SNES { + +#include "serialization.cpp" +#include "algorithms.cpp" +#include "disassembler/disassembler.cpp" + +#define A 0 +#define X 1 +#define Y 2 +#define SP 3 + +#include "opcode_mov.cpp" +#include "opcode_pc.cpp" +#include "opcode_read.cpp" +#include "opcode_rmw.cpp" +#include "opcode_misc.cpp" +#include "table.cpp" + +#undef A +#undef X +#undef Y +#undef SP + +SMPcore::SMPcore() { + initialize_opcode_table(); +} + +} diff --git a/snes/smp/core/core.hpp b/snes/smp/core/core.hpp new file mode 100755 index 00000000..5b14a88f --- /dev/null +++ b/snes/smp/core/core.hpp @@ -0,0 +1,117 @@ +struct SMPcore { + #include "registers.hpp" + #include "memory.hpp" + #include "disassembler/disassembler.hpp" + + regs_t regs; + uint16 dp, sp, rd, wr, bit, ya; + + virtual void op_io() = 0; + virtual uint8 op_read(uint16 addr) = 0; + virtual void op_write(uint16 addr, uint8 data) = 0; + + uint8 op_adc (uint8 x, uint8 y); + uint16 op_addw(uint16 x, uint16 y); + uint8 op_and (uint8 x, uint8 y); + uint8 op_cmp (uint8 x, uint8 y); + uint16 op_cmpw(uint16 x, uint16 y); + uint8 op_eor (uint8 x, uint8 y); + uint8 op_inc (uint8 x); + uint8 op_dec (uint8 x); + uint8 op_or (uint8 x, uint8 y); + uint8 op_sbc (uint8 x, uint8 y); + uint16 op_subw(uint16 x, uint16 y); + uint8 op_asl (uint8 x); + uint8 op_lsr (uint8 x); + uint8 op_rol (uint8 x); + uint8 op_ror (uint8 x); + + template void op_mov_reg_reg(); + void op_mov_sp_x(); + template void op_mov_reg_const(); + void op_mov_a_ix(); + void op_mov_a_ixinc(); + template void op_mov_reg_dp(); + template void op_mov_reg_dpr(); + template void op_mov_reg_addr(); + template void op_mov_a_addrr(); + void op_mov_a_idpx(); + void op_mov_a_idpy(); + void op_mov_dp_dp(); + void op_mov_dp_const(); + void op_mov_ix_a(); + void op_mov_ixinc_a(); + template void op_mov_dp_reg(); + template void op_mov_dpr_reg(); + template void op_mov_addr_reg(); + template void op_mov_addrr_a(); + void op_mov_idpx_a(); + void op_mov_idpy_a(); + void op_movw_ya_dp(); + void op_movw_dp_ya(); + void op_mov1_c_bit(); + void op_mov1_bit_c(); + + void op_bra(); + template void op_branch(); + template void op_bitbranch(); + void op_cbne_dp(); + void op_cbne_dpx(); + void op_dbnz_dp(); + void op_dbnz_y(); + void op_jmp_addr(); + void op_jmp_iaddrx(); + void op_call(); + void op_pcall(); + template void op_tcall(); + void op_brk(); + void op_ret(); + void op_reti(); + + template void op_read_reg_const(); + template void op_read_a_ix(); + template void op_read_reg_dp(); + template void op_read_a_dpx(); + template void op_read_reg_addr(); + template void op_read_a_addrr(); + template void op_read_a_idpx(); + template void op_read_a_idpy(); + template void op_read_ix_iy(); + template void op_read_dp_dp(); + template void op_read_dp_const(); + template void op_read_ya_dp(); + void op_cmpw_ya_dp(); + template void op_and1_bit(); + void op_eor1_bit(); + void op_not1_bit(); + template void op_or1_bit(); + + template void op_adjust_reg(); + template void op_adjust_dp(); + template void op_adjust_dpx(); + template void op_adjust_addr(); + template void op_adjust_addr_a(); + template void op_adjustw_dp(); + + void op_nop(); + void op_wait(); + void op_xcn(); + void op_daa(); + void op_das(); + template void op_setbit(); + void op_notc(); + template void op_seti(); + template void op_setbit_dp(); + template void op_push_reg(); + void op_push_p(); + template void op_pop_reg(); + void op_pop_p(); + void op_mul_ya(); + void op_div_ya_x(); + + void (SMPcore::*opcode_table[256])(); + void initialize_opcode_table(); + + void core_serialize(serializer&); + SMPcore(); +}; diff --git a/snes/smp/core/disassembler/disassembler.cpp b/snes/smp/core/disassembler/disassembler.cpp new file mode 100755 index 00000000..f41fdc6a --- /dev/null +++ b/snes/smp/core/disassembler/disassembler.cpp @@ -0,0 +1,308 @@ +#ifdef SMPCORE_CPP + +uint8 SMPcore::disassemble_read(uint16 addr) { + if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f]; + return smp.apuram[addr]; +} + +uint16 SMPcore::relb(int8 offset, int op_len) { + uint16 pc = regs.pc + op_len; + return pc + offset; +} + +void SMPcore::disassemble_opcode(char *output, uint16 addr) { + char *s, t[512]; + uint8 op, op0, op1; + uint16 opw, opdp0, opdp1; + s = output; + + sprintf(s, "..%.4x ", addr); + + op = disassemble_read(addr + 0); + op0 = disassemble_read(addr + 1); + op1 = disassemble_read(addr + 2); + opw = (op0) | (op1 << 8); + opdp0 = ((unsigned)regs.p.p << 8) + op0; + opdp1 = ((unsigned)regs.p.p << 8) + op1; + + strcpy(t, " "); + + switch(op) { + case 0x00: sprintf(t, "nop"); break; + case 0x01: sprintf(t, "tcall 0"); break; + case 0x02: sprintf(t, "set0 $%.3x", opdp0); break; + case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x04: sprintf(t, "or a,$%.3x", opdp0); break; + case 0x05: sprintf(t, "or a,$%.4x", opw); break; + case 0x06: sprintf(t, "or a,(x)"); break; + case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break; + case 0x08: sprintf(t, "or a,#$%.2x", op0); break; + case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break; + case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x0b: sprintf(t, "asl $%.3x", opdp0); break; + case 0x0c: sprintf(t, "asl $%.4x", opw); break; + case 0x0d: sprintf(t, "push p"); break; + case 0x0e: sprintf(t, "tset $%.4x,a", opw); break; + case 0x0f: sprintf(t, "brk"); break; + case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break; + case 0x11: sprintf(t, "tcall 1"); break; + case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break; + case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break; + case 0x15: sprintf(t, "or a,$%.4x+x", opw); break; + case 0x16: sprintf(t, "or a,$%.4x+y", opw); break; + case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break; + case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break; + case 0x19: sprintf(t, "or (x),(y)"); break; + case 0x1a: sprintf(t, "decw $%.3x", opdp0); break; + case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break; + case 0x1c: sprintf(t, "asl a"); break; + case 0x1d: sprintf(t, "dec x"); break; + case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break; + case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break; + case 0x20: sprintf(t, "clrp"); break; + case 0x21: sprintf(t, "tcall 2"); break; + case 0x22: sprintf(t, "set1 $%.3x", opdp0); break; + case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x24: sprintf(t, "and a,$%.3x", opdp0); break; + case 0x25: sprintf(t, "and a,$%.4x", opw); break; + case 0x26: sprintf(t, "and a,(x)"); break; + case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break; + case 0x28: sprintf(t, "and a,#$%.2x", op0); break; + case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break; + case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x2b: sprintf(t, "rol $%.3x", opdp0); break; + case 0x2c: sprintf(t, "rol $%.4x", opw); break; + case 0x2d: sprintf(t, "push a"); break; + case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break; + case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break; + case 0x31: sprintf(t, "tcall 3"); break; + case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break; + case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break; + case 0x35: sprintf(t, "and a,$%.4x+x", opw); break; + case 0x36: sprintf(t, "and a,$%.4x+y", opw); break; + case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break; + case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break; + case 0x39: sprintf(t, "and (x),(y)"); break; + case 0x3a: sprintf(t, "incw $%.3x", opdp0); break; + case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break; + case 0x3c: sprintf(t, "rol a"); break; + case 0x3d: sprintf(t, "inc x"); break; + case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break; + case 0x3f: sprintf(t, "call $%.4x", opw); break; + case 0x40: sprintf(t, "setp"); break; + case 0x41: sprintf(t, "tcall 4"); break; + case 0x42: sprintf(t, "set2 $%.3x", opdp0); break; + case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break; + case 0x45: sprintf(t, "eor a,$%.4x", opw); break; + case 0x46: sprintf(t, "eor a,(x)"); break; + case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break; + case 0x48: sprintf(t, "eor a,#$%.2x", op0); break; + case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break; + case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break; + case 0x4c: sprintf(t, "lsr $%.4x", opw); break; + case 0x4d: sprintf(t, "push x"); break; + case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break; + case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break; + case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break; + case 0x51: sprintf(t, "tcall 5"); break; + case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break; + case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break; + case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break; + case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break; + case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break; + case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break; + case 0x59: sprintf(t, "eor (x),(y)"); break; + case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break; + case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break; + case 0x5c: sprintf(t, "lsr a"); break; + case 0x5d: sprintf(t, "mov x,a"); break; + case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break; + case 0x5f: sprintf(t, "jmp $%.4x", opw); break; + case 0x60: sprintf(t, "clrc"); break; + case 0x61: sprintf(t, "tcall 6"); break; + case 0x62: sprintf(t, "set3 $%.3x", opdp0); break; + case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break; + case 0x65: sprintf(t, "cmp a,$%.4x", opw); break; + case 0x66: sprintf(t, "cmp a,(x)"); break; + case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break; + case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break; + case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break; + case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x6b: sprintf(t, "ror $%.3x", opdp0); break; + case 0x6c: sprintf(t, "ror $%.4x", opw); break; + case 0x6d: sprintf(t, "push y"); break; + case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x6f: sprintf(t, "ret"); break; + case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break; + case 0x71: sprintf(t, "tcall 7"); break; + case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break; + case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break; + case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break; + case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break; + case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break; + case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break; + case 0x79: sprintf(t, "cmp (x),(y)"); break; + case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break; + case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break; + case 0x7c: sprintf(t, "ror a"); break; + case 0x7d: sprintf(t, "mov a,x"); break; + case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break; + case 0x7f: sprintf(t, "reti"); break; + case 0x80: sprintf(t, "setc"); break; + case 0x81: sprintf(t, "tcall 8"); break; + case 0x82: sprintf(t, "set4 $%.3x", opdp0); break; + case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break; + case 0x85: sprintf(t, "adc a,$%.4x", opw); break; + case 0x86: sprintf(t, "adc a,(x)"); break; + case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break; + case 0x88: sprintf(t, "adc a,#$%.2x", op0); break; + case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break; + case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x8b: sprintf(t, "dec $%.3x", opdp0); break; + case 0x8c: sprintf(t, "dec $%.4x", opw); break; + case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break; + case 0x8e: sprintf(t, "pop p"); break; + case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break; + case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break; + case 0x91: sprintf(t, "tcall 9"); break; + case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break; + case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break; + case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break; + case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break; + case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break; + case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break; + case 0x99: sprintf(t, "adc (x),(y)"); break; + case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break; + case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break; + case 0x9c: sprintf(t, "dec a"); break; + case 0x9d: sprintf(t, "mov x,sp"); break; + case 0x9e: sprintf(t, "div ya,x"); break; + case 0x9f: sprintf(t, "xcn a"); break; + case 0xa0: sprintf(t, "ei"); break; + case 0xa1: sprintf(t, "tcall 10"); break; + case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break; + case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break; + case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break; + case 0xa6: sprintf(t, "sbc a,(x)"); break; + case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break; + case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break; + case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break; + case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xab: sprintf(t, "inc $%.3x", opdp0); break; + case 0xac: sprintf(t, "inc $%.4x", opw); break; + case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break; + case 0xae: sprintf(t, "pop a"); break; + case 0xaf: sprintf(t, "mov (x)+,a"); break; + case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break; + case 0xb1: sprintf(t, "tcall 11"); break; + case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break; + case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break; + case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break; + case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break; + case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break; + case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break; + case 0xb9: sprintf(t, "sbc (x),(y)"); break; + case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break; + case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break; + case 0xbc: sprintf(t, "inc a"); break; + case 0xbd: sprintf(t, "mov sp,x"); break; + case 0xbe: sprintf(t, "das a"); break; + case 0xbf: sprintf(t, "mov a,(x)+"); break; + case 0xc0: sprintf(t, "di"); break; + case 0xc1: sprintf(t, "tcall 12"); break; + case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break; + case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break; + case 0xc5: sprintf(t, "mov $%.4x,a", opw); break; + case 0xc6: sprintf(t, "mov (x),a"); break; + case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break; + case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break; + case 0xc9: sprintf(t, "mov $%.4x,x", opw); break; + case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break; + case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break; + case 0xcc: sprintf(t, "mov $%.4x,y", opw); break; + case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break; + case 0xce: sprintf(t, "pop x"); break; + case 0xcf: sprintf(t, "mul ya"); break; + case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break; + case 0xd1: sprintf(t, "tcall 13"); break; + case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break; + case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break; + case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break; + case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break; + case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break; + case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break; + case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break; + case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break; + case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break; + case 0xdc: sprintf(t, "dec y"); break; + case 0xdd: sprintf(t, "mov a,y"); break; + case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xdf: sprintf(t, "daa a"); break; + case 0xe0: sprintf(t, "clrv"); break; + case 0xe1: sprintf(t, "tcall 14"); break; + case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break; + case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break; + case 0xe5: sprintf(t, "mov a,$%.4x", opw); break; + case 0xe6: sprintf(t, "mov a,(x)"); break; + case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break; + case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break; + case 0xe9: sprintf(t, "mov x,$%.4x", opw); break; + case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break; + case 0xec: sprintf(t, "mov y,$%.4x", opw); break; + case 0xed: sprintf(t, "notc"); break; + case 0xee: sprintf(t, "pop y"); break; + case 0xef: sprintf(t, "sleep"); break; + case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break; + case 0xf1: sprintf(t, "tcall 15"); break; + case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break; + case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break; + case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break; + case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break; + case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break; + case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break; + case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break; + case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break; + case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break; + case 0xfc: sprintf(t, "inc y"); break; + case 0xfd: sprintf(t, "mov y,a"); break; + case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break; + case 0xff: sprintf(t, "stop"); break; + } + + t[strlen(t)] = ' '; + strcat(s, t); + + sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ", + regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya); + strcat(s, t); + + sprintf(t, "%c%c%c%c%c%c%c%c", + regs.p.n ? 'N' : 'n', + regs.p.v ? 'V' : 'v', + regs.p.p ? 'P' : 'p', + regs.p.b ? 'B' : 'b', + regs.p.h ? 'H' : 'h', + regs.p.i ? 'I' : 'i', + regs.p.z ? 'Z' : 'z', + regs.p.c ? 'C' : 'c'); + strcat(s, t); +} + +#endif diff --git a/snes/smp/core/disassembler/disassembler.hpp b/snes/smp/core/disassembler/disassembler.hpp new file mode 100755 index 00000000..a6e78e09 --- /dev/null +++ b/snes/smp/core/disassembler/disassembler.hpp @@ -0,0 +1,3 @@ +void disassemble_opcode(char *output, uint16 addr); +inline uint8 disassemble_read(uint16 addr); +inline uint16 relb(int8 offset, int op_len); diff --git a/snes/smp/core/memory.hpp b/snes/smp/core/memory.hpp new file mode 100755 index 00000000..4b7afba0 --- /dev/null +++ b/snes/smp/core/memory.hpp @@ -0,0 +1,19 @@ +alwaysinline uint8_t op_readpc() { + return op_read(regs.pc++); +} + +alwaysinline uint8_t op_readsp() { + return op_read(0x0100 | ++regs.sp); +} + +alwaysinline void op_writesp(uint8_t data) { + op_write(0x0100 | regs.sp--, data); +} + +alwaysinline uint8_t op_readdp(uint8_t addr) { + return op_read(((unsigned)regs.p.p << 8) + addr); +} + +alwaysinline void op_writedp(uint8_t addr, uint8_t data) { + op_write(((unsigned)regs.p.p << 8) + addr, data); +} diff --git a/snes/smp/core/opcode_misc.cpp b/snes/smp/core/opcode_misc.cpp new file mode 100755 index 00000000..533c8f96 --- /dev/null +++ b/snes/smp/core/opcode_misc.cpp @@ -0,0 +1,148 @@ +#ifdef SMPCORE_CPP + +void SMPcore::op_nop() { + op_io(); +} + +void SMPcore::op_wait() { + while(true) { + op_io(); + op_io(); + } +} + +void SMPcore::op_xcn() { + op_io(); + op_io(); + op_io(); + op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void SMPcore::op_daa() { + op_io(); + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void SMPcore::op_das() { + op_io(); + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +template void SMPcore::op_setbit() { + op_io(); + regs.p = (regs.p & ~mask) | value; +} + +void SMPcore::op_notc() { + op_io(); + op_io(); + regs.p.c = !regs.p.c; +} + +template void SMPcore::op_seti() { + op_io(); + op_io(); + regs.p.i = value; +} + +template void SMPcore::op_setbit_dp() { + dp = op_readpc(); + rd = op_readdp(dp); + rd = (op ? rd | value : rd & ~value); + op_writedp(dp, rd); +} + +template void SMPcore::op_push_reg() { + op_io(); + op_io(); + op_writesp(regs.r[n]); +} + +void SMPcore::op_push_p() { + op_io(); + op_io(); + op_writesp(regs.p); +} + +template void SMPcore::op_pop_reg() { + op_io(); + op_io(); + regs.r[n] = op_readsp(); +} + +void SMPcore::op_pop_p() { + op_io(); + op_io(); + regs.p = op_readsp(); +} + +void SMPcore::op_mul_ya() { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = (regs.y & 0x80); + regs.p.z = (regs.y == 0); +} + +void SMPcore::op_div_ya_x() { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = (regs.y >= regs.x); + regs.p.h = ((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +#endif diff --git a/snes/smp/core/opcode_mov.cpp b/snes/smp/core/opcode_mov.cpp new file mode 100755 index 00000000..f1767855 --- /dev/null +++ b/snes/smp/core/opcode_mov.cpp @@ -0,0 +1,200 @@ +#ifdef SMPCORE_CPP + +template void SMPcore::op_mov_reg_reg() { + op_io(); + regs.r[to] = regs.r[from]; + regs.p.n = (regs.r[to] & 0x80); + regs.p.z = (regs.r[to] == 0); +} + +void SMPcore::op_mov_sp_x() { + op_io(); + regs.sp = regs.x; +} + +template void SMPcore::op_mov_reg_const() { + regs.r[n] = op_readpc(); + regs.p.n = (regs.r[n] & 0x80); + regs.p.z = (regs.r[n] == 0); +} + +void SMPcore::op_mov_a_ix() { + op_io(); + regs.a = op_readdp(regs.x); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void SMPcore::op_mov_a_ixinc() { + op_io(); + regs.a = op_readdp(regs.x++); + op_io(); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +template void SMPcore::op_mov_reg_dp() { + sp = op_readpc(); + regs.r[n] = op_readdp(sp); + regs.p.n = (regs.r[n] & 0x80); + regs.p.z = (regs.r[n] == 0); +} + +template void SMPcore::op_mov_reg_dpr() { + sp = op_readpc(); + op_io(); + regs.r[n] = op_readdp(sp + regs.r[i]); + regs.p.n = (regs.r[n] & 0x80); + regs.p.z = (regs.r[n] == 0); +} + +template void SMPcore::op_mov_reg_addr() { + sp = op_readpc() << 0; + sp |= op_readpc() << 8; + regs.r[n] = op_read(sp); + regs.p.n = (regs.r[n] & 0x80); + regs.p.z = (regs.r[n] == 0); +} + +template void SMPcore::op_mov_a_addrr() { + sp = op_readpc() << 0; + sp |= op_readpc() << 8; + op_io(); + regs.a = op_read(sp + regs.r[i]); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void SMPcore::op_mov_a_idpx() { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp + 0) << 0; + sp |= op_readdp(dp + 1) << 8; + regs.a = op_read(sp); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void SMPcore::op_mov_a_idpy() { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + 0) << 0; + sp |= op_readdp(dp + 1) << 8; + regs.a = op_read(sp + regs.y); + regs.p.n = (regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +void SMPcore::op_mov_dp_dp() { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + op_writedp(dp, rd); +} + +void SMPcore::op_mov_dp_const() { + rd = op_readpc(); + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, rd); +} + +void SMPcore::op_mov_ix_a() { + op_io(); + op_readdp(regs.x); + op_writedp(regs.x, regs.a); +} + +void SMPcore::op_mov_ixinc_a() { + op_io(); + op_io(); + op_writedp(regs.x++, regs.a); +} + +template void SMPcore::op_mov_dp_reg() { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.r[n]); +} + +template void SMPcore::op_mov_dpr_reg() { + dp = op_readpc(); + op_io(); + dp += regs.r[i]; + op_readdp(dp); + op_writedp(dp, regs.r[n]); +} + +template void SMPcore::op_mov_addr_reg() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + op_read(dp); + op_write(dp, regs.r[n]); +} + +template void SMPcore::op_mov_addrr_a() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + op_io(); + dp += regs.r[i]; + op_read(dp); + op_write(dp, regs.a); +} + +void SMPcore::op_mov_idpx_a() { + sp = op_readpc(); + op_io(); + sp += regs.x; + dp = op_readdp(sp + 0) << 0; + dp |= op_readdp(sp + 1) << 8; + op_read(dp); + op_write(dp, regs.a); +} + +void SMPcore::op_mov_idpy_a() { + sp = op_readpc(); + dp = op_readdp(sp + 0) << 0; + dp |= op_readdp(sp + 1) << 8; + op_io(); + dp += regs.y; + op_read(dp); + op_write(dp, regs.a); +} + +void SMPcore::op_movw_ya_dp() { + sp = op_readpc(); + regs.a = op_readdp(sp + 0); + op_io(); + regs.y = op_readdp(sp + 1); + regs.p.n = (regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); +} + +void SMPcore::op_movw_dp_ya() { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp + 0, regs.a); + op_writedp(dp + 1, regs.y); +} + +void SMPcore::op_mov1_c_bit() { + sp = op_readpc() << 0; + sp |= op_readpc() << 8; + bit = sp >> 13; + sp &= 0x1fff; + rd = op_read(sp); + regs.p.c = (rd & (1 << bit)); +} + +void SMPcore::op_mov1_bit_c() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_read(dp); + (regs.p.c) ? rd |= (1 << bit) : rd &= ~(1 << bit); + op_io(); + op_write(dp, rd); +} + +#endif diff --git a/snes/smp/core/opcode_pc.cpp b/snes/smp/core/opcode_pc.cpp new file mode 100755 index 00000000..727522c8 --- /dev/null +++ b/snes/smp/core/opcode_pc.cpp @@ -0,0 +1,152 @@ +#ifdef SMPCORE_CPP + +void SMPcore::op_bra() { + rd = op_readpc(); + op_io(); + op_io(); + regs.pc += (int8)rd; +} + +template void SMPcore::op_branch() { + rd = op_readpc(); + if((bool)(regs.p & flag) != value) return; + op_io(); + op_io(); + regs.pc += (int8)rd; +} + +template void SMPcore::op_bitbranch() { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((bool)(sp & mask) != value) return; + op_io(); + op_io(); + regs.pc += (int8)rd; +} + +void SMPcore::op_cbne_dp() { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if(regs.a == sp) return; + op_io(); + op_io(); + regs.pc += (int8)rd; +} + +void SMPcore::op_cbne_dpx() { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + regs.x); + rd = op_readpc(); + op_io(); + if(regs.a == sp) return; + op_io(); + op_io(); + regs.pc += (int8)rd; +} + +void SMPcore::op_dbnz_dp() { + dp = op_readpc(); + wr = op_readdp(dp); + op_writedp(dp, --wr); + rd = op_readpc(); + if(wr == 0) return; + op_io(); + op_io(); + regs.pc += (int8)rd; +} + +void SMPcore::op_dbnz_y() { + rd = op_readpc(); + op_io(); + regs.y--; + op_io(); + if(regs.y == 0) return; + op_io(); + op_io(); + regs.pc += (int8)rd; +} + +void SMPcore::op_jmp_addr() { + rd = op_readpc() << 0; + rd |= op_readpc() << 8; + regs.pc = rd; +} + +void SMPcore::op_jmp_iaddrx() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + rd = op_read(dp + 0) << 0; + rd |= op_read(dp + 1) << 8; + regs.pc = rd; +} + +void SMPcore::op_call() { + rd = op_readpc() << 0; + rd |= op_readpc() << 8; + op_io(); + op_io(); + op_io(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + regs.pc = rd; +} + +void SMPcore::op_pcall() { + rd = op_readpc(); + op_io(); + op_io(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + regs.pc = 0xff00 | rd; +} + +template void SMPcore::op_tcall() { + dp = 0xffde - (n << 1); + rd = op_read(dp + 0) << 0; + rd |= op_read(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + regs.pc = rd; +} + +void SMPcore::op_brk() { + rd = op_read(0xffde) << 0; + rd |= op_read(0xffdf) << 8; + op_io(); + op_io(); + op_writesp(regs.pc >> 8); + op_writesp(regs.pc >> 0); + op_writesp(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; +} + +void SMPcore::op_ret() { + rd = op_readsp() << 0; + rd |= op_readsp() << 8; + op_io(); + op_io(); + regs.pc = rd; +} + +void SMPcore::op_reti() { + regs.p = op_readsp(); + rd = op_readsp() << 0; + rd |= op_readsp() << 8; + op_io(); + op_io(); + regs.pc = rd; +} + +#endif diff --git a/snes/smp/core/opcode_read.cpp b/snes/smp/core/opcode_read.cpp new file mode 100755 index 00000000..25a5bc06 --- /dev/null +++ b/snes/smp/core/opcode_read.cpp @@ -0,0 +1,154 @@ +#ifdef SMPCORE_CPP + +template +void SMPcore::op_read_reg_const() { + rd = op_readpc(); + regs.r[n] = (this->*op)(regs.r[n], rd); +} + +template +void SMPcore::op_read_a_ix() { + op_io(); + rd = op_readdp(regs.x); + regs.a = (this->*op)(regs.a, rd); +} + +template +void SMPcore::op_read_reg_dp() { + dp = op_readpc(); + rd = op_readdp(dp); + regs.r[n] = (this->*op)(regs.r[n], rd); +} + +template +void SMPcore::op_read_a_dpx() { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = (this->*op)(regs.a, rd); +} + +template +void SMPcore::op_read_reg_addr() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + rd = op_read(dp); + regs.r[n] = (this->*op)(regs.r[n], rd); +} + +template +void SMPcore::op_read_a_addrr() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + op_io(); + rd = op_read(dp + regs.r[i]); + regs.a = (this->*op)(regs.a, rd); +} + +template +void SMPcore::op_read_a_idpx() { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp + 0) << 0; + sp |= op_readdp(dp + 1) << 8; + rd = op_read(sp); + regs.a = (this->*op)(regs.a, rd); +} + +template +void SMPcore::op_read_a_idpy() { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + 0) << 0; + sp |= op_readdp(dp + 1) << 8; + rd = op_read(sp + regs.y); + regs.a = (this->*op)(regs.a, rd); +} + +template +void SMPcore::op_read_ix_iy() { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = (this->*op)(wr, rd); + static uint8 (SMPcore::*cmp)(uint8, uint8) = &SMPcore::op_cmp; + (op != cmp) ? op_writedp(regs.x, wr) : op_io(); +} + +template +void SMPcore::op_read_dp_dp() { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = (this->*op)(wr, rd); + static uint8 (SMPcore::*cmp)(uint8, uint8) = &SMPcore::op_cmp; + (op != cmp) ? op_writedp(dp, wr) : op_io(); +} + +template +void SMPcore::op_read_dp_const() { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = (this->*op)(wr, rd); + static uint8 (SMPcore::*cmp)(uint8, uint8) = &SMPcore::op_cmp; + (op != cmp) ? op_writedp(dp, wr) : op_io(); +} + +template +void SMPcore::op_read_ya_dp() { + dp = op_readpc(); + rd = op_readdp(dp + 0) << 0; + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = (this->*op)(regs.ya, rd); +} + +void SMPcore::op_cmpw_ya_dp() { + dp = op_readpc(); + rd = op_readdp(dp + 0) << 0; + rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); +} + +template void SMPcore::op_and1_bit() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_read(dp); + regs.p.c = regs.p.c & ((bool)(rd & (1 << bit)) ^ op); +} + +void SMPcore::op_eor1_bit() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_read(dp); + op_io(); + regs.p.c = regs.p.c ^ (bool)(rd & (1 << bit)); +} + +void SMPcore::op_not1_bit() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_read(dp); + rd ^= 1 << bit; + op_write(dp, rd); +} + +template void SMPcore::op_or1_bit() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_read(dp); + op_io(); + regs.p.c = regs.p.c | ((bool)(rd & (1 << bit)) ^ op); +} + +#endif diff --git a/snes/smp/core/opcode_rmw.cpp b/snes/smp/core/opcode_rmw.cpp new file mode 100755 index 00000000..df59f490 --- /dev/null +++ b/snes/smp/core/opcode_rmw.cpp @@ -0,0 +1,58 @@ +#ifdef SMPCORE_CPP + +template +void SMPcore::op_adjust_reg() { + op_io(); + regs.r[n] = (this->*op)(regs.r[n]); +} + +template +void SMPcore::op_adjust_dp() { + dp = op_readpc(); + rd = op_readdp(dp); + rd = (this->*op)(rd); + op_writedp(dp, rd); +} + +template +void SMPcore::op_adjust_dpx() { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = (this->*op)(rd); + op_writedp(dp + regs.x, rd); +} + +template +void SMPcore::op_adjust_addr() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + rd = op_read(dp); + rd = (this->*op)(rd); + op_write(dp, rd); +} + +template +void SMPcore::op_adjust_addr_a() { + dp = op_readpc() << 0; + dp |= op_readpc() << 8; + rd = op_read(dp); + regs.p.n = ((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_read(dp); + op_write(dp, (op ? rd | regs.a : rd & ~regs.a)); +} + +template +void SMPcore::op_adjustw_dp() { + dp = op_readpc(); + rd = op_readdp(dp) << 0; + rd += adjust; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = (rd & 0x8000); + regs.p.z = (rd == 0); +} + +#endif diff --git a/snes/smp/core/registers.hpp b/snes/smp/core/registers.hpp new file mode 100755 index 00000000..baed447b --- /dev/null +++ b/snes/smp/core/registers.hpp @@ -0,0 +1,44 @@ +struct regya_t { + uint8_t &hi, &lo; + + inline operator uint16_t() const { + return (hi << 8) + lo; + } + + inline regya_t& operator=(uint16_t data) { + hi = data >> 8; + lo = data; + return *this; + } + + regya_t(uint8_t &hi_, uint8_t &lo_) : hi(hi_), lo(lo_) {} +}; + +struct flag_t { + bool n, v, p, b, h, i, z, c; + + inline operator unsigned() const { + return (n << 7) + (v << 6) + (p << 5) + (b << 4) + + (h << 3) + (i << 2) + (z << 1) + (c << 0); + } + + inline unsigned operator=(uint8_t data) { + n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10; + h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01; + return data; + } + + inline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); } + inline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); } + inline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); } + + flag_t() : n(0), v(0), p(0), b(0), h(0), i(0), z(0), c(0) {} +}; + +struct regs_t { + uint16_t pc; + uint8_t r[4], &a, &x, &y, &sp; + regya_t ya; + flag_t p; + regs_t() : a(r[0]), x(r[1]), y(r[2]), sp(r[3]), ya(r[2], r[0]) {} +}; diff --git a/snes/smp/core/serialization.cpp b/snes/smp/core/serialization.cpp new file mode 100755 index 00000000..883d013c --- /dev/null +++ b/snes/smp/core/serialization.cpp @@ -0,0 +1,26 @@ +#ifdef SMPCORE_CPP + +void SMPcore::core_serialize(serializer &s) { + s.integer(regs.pc); + s.integer(regs.a); + s.integer(regs.x); + s.integer(regs.y); + s.integer(regs.sp); + s.integer(regs.p.n); + s.integer(regs.p.v); + s.integer(regs.p.p); + s.integer(regs.p.b); + s.integer(regs.p.h); + s.integer(regs.p.i); + s.integer(regs.p.z); + s.integer(regs.p.c); + + s.integer(dp); + s.integer(sp); + s.integer(rd); + s.integer(wr); + s.integer(bit); + s.integer(ya); +} + +#endif diff --git a/snes/smp/core/table.cpp b/snes/smp/core/table.cpp new file mode 100755 index 00000000..dc0f633a --- /dev/null +++ b/snes/smp/core/table.cpp @@ -0,0 +1,264 @@ +#ifdef SMPCORE_CPP + +void SMPcore::initialize_opcode_table() { + #define op opcode_table + op[0x00] = &SMPcore::op_nop; + op[0x01] = &SMPcore::op_tcall<0>; + op[0x02] = &SMPcore::op_setbit_dp<1, 0x01>; + op[0x03] = &SMPcore::op_bitbranch<0x01, true>; + op[0x04] = &SMPcore::op_read_reg_dp<&SMPcore::op_or, A>; + op[0x05] = &SMPcore::op_read_reg_addr<&SMPcore::op_or, A>; + op[0x06] = &SMPcore::op_read_a_ix<&SMPcore::op_or>; + op[0x07] = &SMPcore::op_read_a_idpx<&SMPcore::op_or>; + op[0x08] = &SMPcore::op_read_reg_const<&SMPcore::op_or, A>; + op[0x09] = &SMPcore::op_read_dp_dp<&SMPcore::op_or>; + op[0x0a] = &SMPcore::op_or1_bit<0>; + op[0x0b] = &SMPcore::op_adjust_dp<&SMPcore::op_asl>; + op[0x0c] = &SMPcore::op_adjust_addr<&SMPcore::op_asl>; + op[0x0d] = &SMPcore::op_push_p; + op[0x0e] = &SMPcore::op_adjust_addr_a<1>; + op[0x0f] = &SMPcore::op_brk; + op[0x10] = &SMPcore::op_branch<0x80, false>; + op[0x11] = &SMPcore::op_tcall<1>; + op[0x12] = &SMPcore::op_setbit_dp<0, 0x01>; + op[0x13] = &SMPcore::op_bitbranch<0x01, false>; + op[0x14] = &SMPcore::op_read_a_dpx<&SMPcore::op_or>; + op[0x15] = &SMPcore::op_read_a_addrr<&SMPcore::op_or, X>; + op[0x16] = &SMPcore::op_read_a_addrr<&SMPcore::op_or, Y>; + op[0x17] = &SMPcore::op_read_a_idpy<&SMPcore::op_or>; + op[0x18] = &SMPcore::op_read_dp_const<&SMPcore::op_or>; + op[0x19] = &SMPcore::op_read_ix_iy<&SMPcore::op_or>; + op[0x1a] = &SMPcore::op_adjustw_dp<-1>; + op[0x1b] = &SMPcore::op_adjust_dpx<&SMPcore::op_asl>; + op[0x1c] = &SMPcore::op_adjust_reg<&SMPcore::op_asl, A>; + op[0x1d] = &SMPcore::op_adjust_reg<&SMPcore::op_dec, X>; + op[0x1e] = &SMPcore::op_read_reg_addr<&SMPcore::op_cmp, X>; + op[0x1f] = &SMPcore::op_jmp_iaddrx; + op[0x20] = &SMPcore::op_setbit<0x20, 0x00>; + op[0x21] = &SMPcore::op_tcall<2>; + op[0x22] = &SMPcore::op_setbit_dp<1, 0x02>; + op[0x23] = &SMPcore::op_bitbranch<0x02, true>; + op[0x24] = &SMPcore::op_read_reg_dp<&SMPcore::op_and, A>; + op[0x25] = &SMPcore::op_read_reg_addr<&SMPcore::op_and, A>; + op[0x26] = &SMPcore::op_read_a_ix<&SMPcore::op_and>; + op[0x27] = &SMPcore::op_read_a_idpx<&SMPcore::op_and>; + op[0x28] = &SMPcore::op_read_reg_const<&SMPcore::op_and, A>; + op[0x29] = &SMPcore::op_read_dp_dp<&SMPcore::op_and>; + op[0x2a] = &SMPcore::op_or1_bit<1>; + op[0x2b] = &SMPcore::op_adjust_dp<&SMPcore::op_rol>; + op[0x2c] = &SMPcore::op_adjust_addr<&SMPcore::op_rol>; + op[0x2d] = &SMPcore::op_push_reg; + op[0x2e] = &SMPcore::op_cbne_dp; + op[0x2f] = &SMPcore::op_bra; + op[0x30] = &SMPcore::op_branch<0x80, true>; + op[0x31] = &SMPcore::op_tcall<3>; + op[0x32] = &SMPcore::op_setbit_dp<0, 0x02>; + op[0x33] = &SMPcore::op_bitbranch<0x02, false>; + op[0x34] = &SMPcore::op_read_a_dpx<&SMPcore::op_and>; + op[0x35] = &SMPcore::op_read_a_addrr<&SMPcore::op_and, X>; + op[0x36] = &SMPcore::op_read_a_addrr<&SMPcore::op_and, Y>; + op[0x37] = &SMPcore::op_read_a_idpy<&SMPcore::op_and>; + op[0x38] = &SMPcore::op_read_dp_const<&SMPcore::op_and>; + op[0x39] = &SMPcore::op_read_ix_iy<&SMPcore::op_and>; + op[0x3a] = &SMPcore::op_adjustw_dp<+1>; + op[0x3b] = &SMPcore::op_adjust_dpx<&SMPcore::op_rol>; + op[0x3c] = &SMPcore::op_adjust_reg<&SMPcore::op_rol, A>; + op[0x3d] = &SMPcore::op_adjust_reg<&SMPcore::op_inc, X>; + op[0x3e] = &SMPcore::op_read_reg_dp<&SMPcore::op_cmp, X>; + op[0x3f] = &SMPcore::op_call; + op[0x40] = &SMPcore::op_setbit<0x20, 0x20>; + op[0x41] = &SMPcore::op_tcall<4>; + op[0x42] = &SMPcore::op_setbit_dp<1, 0x04>; + op[0x43] = &SMPcore::op_bitbranch<0x04, true>; + op[0x44] = &SMPcore::op_read_reg_dp<&SMPcore::op_eor, A>; + op[0x45] = &SMPcore::op_read_reg_addr<&SMPcore::op_eor, A>; + op[0x46] = &SMPcore::op_read_a_ix<&SMPcore::op_eor>; + op[0x47] = &SMPcore::op_read_a_idpx<&SMPcore::op_eor>; + op[0x48] = &SMPcore::op_read_reg_const<&SMPcore::op_eor, A>; + op[0x49] = &SMPcore::op_read_dp_dp<&SMPcore::op_eor>; + op[0x4a] = &SMPcore::op_and1_bit<0>; + op[0x4b] = &SMPcore::op_adjust_dp<&SMPcore::op_lsr>; + op[0x4c] = &SMPcore::op_adjust_addr<&SMPcore::op_lsr>; + op[0x4d] = &SMPcore::op_push_reg; + op[0x4e] = &SMPcore::op_adjust_addr_a<0>; + op[0x4f] = &SMPcore::op_pcall; + op[0x50] = &SMPcore::op_branch<0x40, false>; + op[0x51] = &SMPcore::op_tcall<5>; + op[0x52] = &SMPcore::op_setbit_dp<0, 0x04>; + op[0x53] = &SMPcore::op_bitbranch<0x04, false>; + op[0x54] = &SMPcore::op_read_a_dpx<&SMPcore::op_eor>; + op[0x55] = &SMPcore::op_read_a_addrr<&SMPcore::op_eor, X>; + op[0x56] = &SMPcore::op_read_a_addrr<&SMPcore::op_eor, Y>; + op[0x57] = &SMPcore::op_read_a_idpy<&SMPcore::op_eor>; + op[0x58] = &SMPcore::op_read_dp_const<&SMPcore::op_eor>; + op[0x59] = &SMPcore::op_read_ix_iy<&SMPcore::op_eor>; + op[0x5a] = &SMPcore::op_cmpw_ya_dp; + op[0x5b] = &SMPcore::op_adjust_dpx<&SMPcore::op_lsr>; + op[0x5c] = &SMPcore::op_adjust_reg<&SMPcore::op_lsr, A>; + op[0x5d] = &SMPcore::op_mov_reg_reg; + op[0x5e] = &SMPcore::op_read_reg_addr<&SMPcore::op_cmp, Y>; + op[0x5f] = &SMPcore::op_jmp_addr; + op[0x60] = &SMPcore::op_setbit<0x01, 0x00>; + op[0x61] = &SMPcore::op_tcall<6>; + op[0x62] = &SMPcore::op_setbit_dp<1, 0x08>; + op[0x63] = &SMPcore::op_bitbranch<0x08, true>; + op[0x64] = &SMPcore::op_read_reg_dp<&SMPcore::op_cmp, A>; + op[0x65] = &SMPcore::op_read_reg_addr<&SMPcore::op_cmp, A>; + op[0x66] = &SMPcore::op_read_a_ix<&SMPcore::op_cmp>; + op[0x67] = &SMPcore::op_read_a_idpx<&SMPcore::op_cmp>; + op[0x68] = &SMPcore::op_read_reg_const<&SMPcore::op_cmp, A>; + op[0x69] = &SMPcore::op_read_dp_dp<&SMPcore::op_cmp>; + op[0x6a] = &SMPcore::op_and1_bit<1>; + op[0x6b] = &SMPcore::op_adjust_dp<&SMPcore::op_ror>; + op[0x6c] = &SMPcore::op_adjust_addr<&SMPcore::op_ror>; + op[0x6d] = &SMPcore::op_push_reg; + op[0x6e] = &SMPcore::op_dbnz_dp; + op[0x6f] = &SMPcore::op_ret; + op[0x70] = &SMPcore::op_branch<0x40, true>; + op[0x71] = &SMPcore::op_tcall<7>; + op[0x72] = &SMPcore::op_setbit_dp<0, 0x08>; + op[0x73] = &SMPcore::op_bitbranch<0x08, false>; + op[0x74] = &SMPcore::op_read_a_dpx<&SMPcore::op_cmp>; + op[0x75] = &SMPcore::op_read_a_addrr<&SMPcore::op_cmp, X>; + op[0x76] = &SMPcore::op_read_a_addrr<&SMPcore::op_cmp, Y>; + op[0x77] = &SMPcore::op_read_a_idpy<&SMPcore::op_cmp>; + op[0x78] = &SMPcore::op_read_dp_const<&SMPcore::op_cmp>; + op[0x79] = &SMPcore::op_read_ix_iy<&SMPcore::op_cmp>; + op[0x7a] = &SMPcore::op_read_ya_dp<&SMPcore::op_addw>; + op[0x7b] = &SMPcore::op_adjust_dpx<&SMPcore::op_ror>; + op[0x7c] = &SMPcore::op_adjust_reg<&SMPcore::op_ror, A>; + op[0x7d] = &SMPcore::op_mov_reg_reg; + op[0x7e] = &SMPcore::op_read_reg_dp<&SMPcore::op_cmp, Y>; + op[0x7f] = &SMPcore::op_reti; + op[0x80] = &SMPcore::op_setbit<0x01, 0x01>; + op[0x81] = &SMPcore::op_tcall<8>; + op[0x82] = &SMPcore::op_setbit_dp<1, 0x10>; + op[0x83] = &SMPcore::op_bitbranch<0x10, true>; + op[0x84] = &SMPcore::op_read_reg_dp<&SMPcore::op_adc, A>; + op[0x85] = &SMPcore::op_read_reg_addr<&SMPcore::op_adc, A>; + op[0x86] = &SMPcore::op_read_a_ix<&SMPcore::op_adc>; + op[0x87] = &SMPcore::op_read_a_idpx<&SMPcore::op_adc>; + op[0x88] = &SMPcore::op_read_reg_const<&SMPcore::op_adc, A>; + op[0x89] = &SMPcore::op_read_dp_dp<&SMPcore::op_adc>; + op[0x8a] = &SMPcore::op_eor1_bit; + op[0x8b] = &SMPcore::op_adjust_dp<&SMPcore::op_dec>; + op[0x8c] = &SMPcore::op_adjust_addr<&SMPcore::op_dec>; + op[0x8d] = &SMPcore::op_mov_reg_const; + op[0x8e] = &SMPcore::op_pop_p; + op[0x8f] = &SMPcore::op_mov_dp_const; + op[0x90] = &SMPcore::op_branch<0x01, false>; + op[0x91] = &SMPcore::op_tcall<9>; + op[0x92] = &SMPcore::op_setbit_dp<0, 0x10>; + op[0x93] = &SMPcore::op_bitbranch<0x10, false>; + op[0x94] = &SMPcore::op_read_a_dpx<&SMPcore::op_adc>; + op[0x95] = &SMPcore::op_read_a_addrr<&SMPcore::op_adc, X>; + op[0x96] = &SMPcore::op_read_a_addrr<&SMPcore::op_adc, Y>; + op[0x97] = &SMPcore::op_read_a_idpy<&SMPcore::op_adc>; + op[0x98] = &SMPcore::op_read_dp_const<&SMPcore::op_adc>; + op[0x99] = &SMPcore::op_read_ix_iy<&SMPcore::op_adc>; + op[0x9a] = &SMPcore::op_read_ya_dp<&SMPcore::op_subw>; + op[0x9b] = &SMPcore::op_adjust_dpx<&SMPcore::op_dec>; + op[0x9c] = &SMPcore::op_adjust_reg<&SMPcore::op_dec, A>; + op[0x9d] = &SMPcore::op_mov_reg_reg; + op[0x9e] = &SMPcore::op_div_ya_x; + op[0x9f] = &SMPcore::op_xcn; + op[0xa0] = &SMPcore::op_seti<1>; + op[0xa1] = &SMPcore::op_tcall<10>; + op[0xa2] = &SMPcore::op_setbit_dp<1, 0x20>; + op[0xa3] = &SMPcore::op_bitbranch<0x20, true>; + op[0xa4] = &SMPcore::op_read_reg_dp<&SMPcore::op_sbc, A>; + op[0xa5] = &SMPcore::op_read_reg_addr<&SMPcore::op_sbc, A>; + op[0xa6] = &SMPcore::op_read_a_ix<&SMPcore::op_sbc>; + op[0xa7] = &SMPcore::op_read_a_idpx<&SMPcore::op_sbc>; + op[0xa8] = &SMPcore::op_read_reg_const<&SMPcore::op_sbc, A>; + op[0xa9] = &SMPcore::op_read_dp_dp<&SMPcore::op_sbc>; + op[0xaa] = &SMPcore::op_mov1_c_bit; + op[0xab] = &SMPcore::op_adjust_dp<&SMPcore::op_inc>; + op[0xac] = &SMPcore::op_adjust_addr<&SMPcore::op_inc>; + op[0xad] = &SMPcore::op_read_reg_const<&SMPcore::op_cmp, Y>; + op[0xae] = &SMPcore::op_pop_reg; + op[0xaf] = &SMPcore::op_mov_ixinc_a; + op[0xb0] = &SMPcore::op_branch<0x01, true>; + op[0xb1] = &SMPcore::op_tcall<11>; + op[0xb2] = &SMPcore::op_setbit_dp<0, 0x20>; + op[0xb3] = &SMPcore::op_bitbranch<0x20, false>; + op[0xb4] = &SMPcore::op_read_a_dpx<&SMPcore::op_sbc>; + op[0xb5] = &SMPcore::op_read_a_addrr<&SMPcore::op_sbc, X>; + op[0xb6] = &SMPcore::op_read_a_addrr<&SMPcore::op_sbc, Y>; + op[0xb7] = &SMPcore::op_read_a_idpy<&SMPcore::op_sbc>; + op[0xb8] = &SMPcore::op_read_dp_const<&SMPcore::op_sbc>; + op[0xb9] = &SMPcore::op_read_ix_iy<&SMPcore::op_sbc>; + op[0xba] = &SMPcore::op_movw_ya_dp; + op[0xbb] = &SMPcore::op_adjust_dpx<&SMPcore::op_inc>; + op[0xbc] = &SMPcore::op_adjust_reg<&SMPcore::op_inc, A>; + op[0xbd] = &SMPcore::op_mov_sp_x; + op[0xbe] = &SMPcore::op_das; + op[0xbf] = &SMPcore::op_mov_a_ixinc; + op[0xc0] = &SMPcore::op_seti<0>; + op[0xc1] = &SMPcore::op_tcall<12>; + op[0xc2] = &SMPcore::op_setbit_dp<1, 0x40>; + op[0xc3] = &SMPcore::op_bitbranch<0x40, true>; + op[0xc4] = &SMPcore::op_mov_dp_reg; + op[0xc5] = &SMPcore::op_mov_addr_reg; + op[0xc6] = &SMPcore::op_mov_ix_a; + op[0xc7] = &SMPcore::op_mov_idpx_a; + op[0xc8] = &SMPcore::op_read_reg_const<&SMPcore::op_cmp, X>; + op[0xc9] = &SMPcore::op_mov_addr_reg; + op[0xca] = &SMPcore::op_mov1_bit_c; + op[0xcb] = &SMPcore::op_mov_dp_reg; + op[0xcc] = &SMPcore::op_mov_addr_reg; + op[0xcd] = &SMPcore::op_mov_reg_const; + op[0xce] = &SMPcore::op_pop_reg; + op[0xcf] = &SMPcore::op_mul_ya; + op[0xd0] = &SMPcore::op_branch<0x02, false>; + op[0xd1] = &SMPcore::op_tcall<13>; + op[0xd2] = &SMPcore::op_setbit_dp<0, 0x40>; + op[0xd3] = &SMPcore::op_bitbranch<0x40, false>; + op[0xd4] = &SMPcore::op_mov_dpr_reg; + op[0xd5] = &SMPcore::op_mov_addrr_a; + op[0xd6] = &SMPcore::op_mov_addrr_a; + op[0xd7] = &SMPcore::op_mov_idpy_a; + op[0xd8] = &SMPcore::op_mov_dp_reg; + op[0xd9] = &SMPcore::op_mov_dpr_reg; + op[0xda] = &SMPcore::op_movw_dp_ya; + op[0xdb] = &SMPcore::op_mov_dpr_reg; + op[0xdc] = &SMPcore::op_adjust_reg<&SMPcore::op_dec, Y>; + op[0xdd] = &SMPcore::op_mov_reg_reg; + op[0xde] = &SMPcore::op_cbne_dpx; + op[0xdf] = &SMPcore::op_daa; + op[0xe0] = &SMPcore::op_setbit<0x48, 0x00>; + op[0xe1] = &SMPcore::op_tcall<14>; + op[0xe2] = &SMPcore::op_setbit_dp<1, 0x80>; + op[0xe3] = &SMPcore::op_bitbranch<0x80, true>; + op[0xe4] = &SMPcore::op_mov_reg_dp; + op[0xe5] = &SMPcore::op_mov_reg_addr; + op[0xe6] = &SMPcore::op_mov_a_ix; + op[0xe7] = &SMPcore::op_mov_a_idpx; + op[0xe8] = &SMPcore::op_mov_reg_const; + op[0xe9] = &SMPcore::op_mov_reg_addr; + op[0xea] = &SMPcore::op_not1_bit; + op[0xeb] = &SMPcore::op_mov_reg_dp; + op[0xec] = &SMPcore::op_mov_reg_addr; + op[0xed] = &SMPcore::op_notc; + op[0xee] = &SMPcore::op_pop_reg; + op[0xef] = &SMPcore::op_wait; + op[0xf0] = &SMPcore::op_branch<0x02, true>; + op[0xf1] = &SMPcore::op_tcall<15>; + op[0xf2] = &SMPcore::op_setbit_dp<0, 0x80>; + op[0xf3] = &SMPcore::op_bitbranch<0x80, false>; + op[0xf4] = &SMPcore::op_mov_reg_dpr; + op[0xf5] = &SMPcore::op_mov_a_addrr; + op[0xf6] = &SMPcore::op_mov_a_addrr; + op[0xf7] = &SMPcore::op_mov_a_idpy; + op[0xf8] = &SMPcore::op_mov_reg_dp; + op[0xf9] = &SMPcore::op_mov_reg_dpr; + op[0xfa] = &SMPcore::op_mov_dp_dp; + op[0xfb] = &SMPcore::op_mov_reg_dpr; + op[0xfc] = &SMPcore::op_adjust_reg<&SMPcore::op_inc, Y>; + op[0xfd] = &SMPcore::op_mov_reg_reg; + op[0xfe] = &SMPcore::op_dbnz_y; + op[0xff] = &SMPcore::op_wait; + #undef op +} + +#endif diff --git a/snes/smp/debugger/debugger.cpp b/snes/smp/debugger/debugger.cpp new file mode 100755 index 00000000..9546c118 --- /dev/null +++ b/snes/smp/debugger/debugger.cpp @@ -0,0 +1,75 @@ +#ifdef SMP_CPP + +void SMPDebugger::op_step() { + bool break_event = false; + + usage[regs.pc] |= UsageExec; + opcode_pc = regs.pc; + + opcode_edge = true; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); + if(step_event && step_event() == true) { + debugger.break_event = Debugger::BreakEvent::SMPStep; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + } + opcode_edge = false; + + SMP::op_step(); + synchronize_cpu(); +} + +uint8 SMPDebugger::op_read(uint16 addr) { + uint8 data = SMP::op_read(addr); + usage[addr] |= UsageRead; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void SMPDebugger::op_write(uint16 addr, uint8 data) { + SMP::op_write(addr, data); + usage[addr] |= UsageWrite; + usage[addr] &= ~UsageExec; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data); +} + +SMPDebugger::SMPDebugger() { + usage = new uint8[1 << 16](); + opcode_pc = 0xffc0; + opcode_edge = false; +} + +SMPDebugger::~SMPDebugger() { + delete[] usage; +} + +bool SMPDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //$00f0 + item("$00f0", ""); + item("Clock Speed", (unsigned)status.clock_speed); + item("Timers Enable", status.timers_enable); + item("RAM Disable", status.ram_disable); + item("RAM Writable", status.ram_writable); + item("Timers Disable", status.timers_disable); + + //$00f1 + item("$00f1", ""); + item("IPLROM Enable", status.iplrom_enable); + + //$00f2 + item("$00f2", ""); + item("DSP Address", string("0x", hex<2>(status.dsp_addr))); + + #undef item + return false; +} + +#endif diff --git a/snes/smp/debugger/debugger.hpp b/snes/smp/debugger/debugger.hpp new file mode 100755 index 00000000..d5d28e53 --- /dev/null +++ b/snes/smp/debugger/debugger.hpp @@ -0,0 +1,22 @@ +class SMPDebugger : public SMP, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + function step_event; + + enum Usage { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + }; + uint8 *usage; + uint16 opcode_pc; + bool opcode_edge; + + void op_step(); + uint8 op_read(uint16 addr); + void op_write(uint16 addr, uint8 data); + + SMPDebugger(); + ~SMPDebugger(); +}; diff --git a/snes/smp/iplrom.cpp b/snes/smp/iplrom.cpp new file mode 100755 index 00000000..a2ade89d --- /dev/null +++ b/snes/smp/iplrom.cpp @@ -0,0 +1,44 @@ +#ifdef SMP_CPP + +//this is the IPLROM for the S-SMP coprocessor. +//the S-SMP does not allow writing to the IPLROM. +//all writes are instead mapped to the extended +//RAM region, accessible when $f1.d7 is clear. + +const uint8 SMP::iplrom[64] = { +/*ffc0*/ 0xcd, 0xef, //mov x,#$ef +/*ffc2*/ 0xbd, //mov sp,x +/*ffc3*/ 0xe8, 0x00, //mov a,#$00 +/*ffc5*/ 0xc6, //mov (x),a +/*ffc6*/ 0x1d, //dec x +/*ffc7*/ 0xd0, 0xfc, //bne $ffc5 +/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa +/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb +/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc +/*ffd2*/ 0xd0, 0xfb, //bne $ffcf +/*ffd4*/ 0x2f, 0x19, //bra $ffef +/*ffd6*/ 0xeb, 0xf4, //mov y,$f4 +/*ffd8*/ 0xd0, 0xfc, //bne $ffd6 +/*ffda*/ 0x7e, 0xf4, //cmp y,$f4 +/*ffdc*/ 0xd0, 0x0b, //bne $ffe9 +/*ffde*/ 0xe4, 0xf5, //mov a,$f5 +/*ffe0*/ 0xcb, 0xf4, //mov $f4,y +/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a +/*ffe4*/ 0xfc, //inc y +/*ffe5*/ 0xd0, 0xf3, //bne $ffda +/*ffe7*/ 0xab, 0x01, //inc $01 +/*ffe9*/ 0x10, 0xef, //bpl $ffda +/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4 +/*ffed*/ 0x10, 0xeb, //bpl $ffda +/*ffef*/ 0xba, 0xf6, //movw ya,$f6 +/*fff1*/ 0xda, 0x00, //movw $00,ya +/*fff3*/ 0xba, 0xf4, //movw ya,$f4 +/*fff5*/ 0xc4, 0xf4, //mov $f4,a +/*fff7*/ 0xdd, //mov a,y +/*fff8*/ 0x5d, //mov x,a +/*fff9*/ 0xd0, 0xdb, //bne $ffd6 +/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x) +/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0) +}; + +#endif diff --git a/snes/smp/memory/memory.cpp b/snes/smp/memory/memory.cpp new file mode 100755 index 00000000..391324c4 --- /dev/null +++ b/snes/smp/memory/memory.cpp @@ -0,0 +1,197 @@ +#ifdef SMP_CPP + +alwaysinline uint8 SMP::ram_read(uint16 addr) { + if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; + if(status.ram_disable) return 0x5a; //0xff on mini-SNES + return apuram[addr]; +} + +alwaysinline void SMP::ram_write(uint16 addr, uint8 data) { + //writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled + if(status.ram_writable && !status.ram_disable) apuram[addr] = data; +} + +uint8 SMP::port_read(uint2 port) const { + return apuram[0xf4 + port]; +} + +void SMP::port_write(uint2 port, uint8 data) { + apuram[0xf4 + port] = data; +} + +alwaysinline uint8 SMP::op_busread(uint16 addr) { + unsigned result; + + switch(addr) { + case 0xf0: //TEST -- write-only register + return 0x00; + + case 0xf1: //CONTROL -- write-only register + return 0x00; + + case 0xf2: //DSPADDR + return status.dsp_addr; + + case 0xf3: //DSPDATA + //0x80-0xff are read-only mirrors of 0x00-0x7f + return dsp.read(status.dsp_addr & 0x7f); + + case 0xf4: //CPUIO0 + case 0xf5: //CPUIO1 + case 0xf6: //CPUIO2 + case 0xf7: //CPUIO3 + synchronize_cpu(); + return cpu.port_read(addr); + + case 0xf8: //RAM0 + return status.ram00f8; + + case 0xf9: //RAM1 + return status.ram00f9; + + case 0xfa: //T0TARGET + case 0xfb: //T1TARGET + case 0xfc: //T2TARGET -- write-only registers + return 0x00; + + case 0xfd: //T0OUT -- 4-bit counter value + result = timer0.stage3_ticks; + timer0.stage3_ticks = 0; + return result; + + case 0xfe: //T1OUT -- 4-bit counter value + result = timer1.stage3_ticks; + timer1.stage3_ticks = 0; + return result; + + case 0xff: //T2OUT -- 4-bit counter value + result = timer2.stage3_ticks; + timer2.stage3_ticks = 0; + return result; + } + + return ram_read(addr); +} + +alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) { + switch(addr) { + case 0xf0: //TEST + if(regs.p.p) break; //writes only valid when P flag is clear + + status.clock_speed = (data >> 6) & 3; + status.timer_speed = (data >> 4) & 3; + status.timers_enable = data & 0x08; + status.ram_disable = data & 0x04; + status.ram_writable = data & 0x02; + status.timers_disable = data & 0x01; + + status.timer_step = (1 << status.clock_speed) + (2 << status.timer_speed); + + timer0.synchronize_stage1(); + timer1.synchronize_stage1(); + timer2.synchronize_stage1(); + break; + + case 0xf1: //CONTROL + status.iplrom_enable = data & 0x80; + + if(data & 0x30) { + //one-time clearing of APU port read registers, + //emulated by simulating CPU writes of 0x00 + synchronize_cpu(); + if(data & 0x20) { + cpu.port_write(2, 0x00); + cpu.port_write(3, 0x00); + } + if(data & 0x10) { + cpu.port_write(0, 0x00); + cpu.port_write(1, 0x00); + } + } + + //0->1 transistion resets timers + if(timer2.enable == false && (data & 0x04)) { + timer2.stage2_ticks = 0; + timer2.stage3_ticks = 0; + } + timer2.enable = data & 0x04; + + if(timer1.enable == false && (data & 0x02)) { + timer1.stage2_ticks = 0; + timer1.stage3_ticks = 0; + } + timer1.enable = data & 0x02; + + if(timer0.enable == false && (data & 0x01)) { + timer0.stage2_ticks = 0; + timer0.stage3_ticks = 0; + } + timer0.enable = data & 0x01; + break; + + case 0xf2: //DSPADDR + status.dsp_addr = data; + break; + + case 0xf3: //DSPDATA + if(status.dsp_addr & 0x80) break; //0x80-0xff are read-only mirrors of 0x00-0x7f + dsp.write(status.dsp_addr & 0x7f, data); + break; + + case 0xf4: //CPUIO0 + case 0xf5: //CPUIO1 + case 0xf6: //CPUIO2 + case 0xf7: //CPUIO3 + synchronize_cpu(); + port_write(addr, data); + break; + + case 0xf8: //RAM0 + status.ram00f8 = data; + break; + + case 0xf9: //RAM1 + status.ram00f9 = data; + break; + + case 0xfa: //T0TARGET + timer0.target = data; + break; + + case 0xfb: //T1TARGET + timer1.target = data; + break; + + case 0xfc: //T2TARGET + timer2.target = data; + break; + + case 0xfd: //T0OUT + case 0xfe: //T1OUT + case 0xff: //T2OUT -- read-only registers + break; + } + + ram_write(addr, data); //all writes, even to MMIO registers, appear on bus +} + +void SMP::op_io() { + add_clocks(24); + cycle_edge(); +} + +uint8 SMP::op_read(uint16 addr) { + add_clocks(12); + uint8 r = op_busread(addr); + add_clocks(12); + cycle_edge(); + return r; +} + +void SMP::op_write(uint16 addr, uint8 data) { + add_clocks(24); + op_buswrite(addr, data); + cycle_edge(); +} + +#endif diff --git a/snes/smp/memory/memory.hpp b/snes/smp/memory/memory.hpp new file mode 100755 index 00000000..1a07445d --- /dev/null +++ b/snes/smp/memory/memory.hpp @@ -0,0 +1,9 @@ +uint8 ram_read(uint16 addr); +void ram_write(uint16 addr, uint8 data); + +uint8 op_busread(uint16 addr); +void op_buswrite(uint16 addr, uint8 data); + +void op_io(); +debugvirtual uint8 op_read(uint16 addr); +debugvirtual void op_write(uint16 addr, uint8 data); diff --git a/snes/smp/serialization.cpp b/snes/smp/serialization.cpp new file mode 100755 index 00000000..c646ad6a --- /dev/null +++ b/snes/smp/serialization.cpp @@ -0,0 +1,52 @@ +#ifdef SMP_CPP + +void SMP::serialize(serializer &s) { + Processor::serialize(s); + SMPcore::core_serialize(s); + + s.array(apuram); + + s.integer(status.clock_counter); + s.integer(status.dsp_counter); + s.integer(status.timer_step); + + s.integer(status.clock_speed); + s.integer(status.timer_speed); + s.integer(status.timers_enable); + s.integer(status.ram_disable); + s.integer(status.ram_writable); + s.integer(status.timers_disable); + + s.integer(status.iplrom_enable); + + s.integer(status.dsp_addr); + + s.integer(status.ram00f8); + s.integer(status.ram00f9); + + s.integer(timer0.stage0_ticks); + s.integer(timer0.stage1_ticks); + s.integer(timer0.stage2_ticks); + s.integer(timer0.stage3_ticks); + s.integer(timer0.current_line); + s.integer(timer0.enable); + s.integer(timer0.target); + + s.integer(timer1.stage0_ticks); + s.integer(timer1.stage1_ticks); + s.integer(timer1.stage2_ticks); + s.integer(timer1.stage3_ticks); + s.integer(timer1.current_line); + s.integer(timer1.enable); + s.integer(timer1.target); + + s.integer(timer2.stage0_ticks); + s.integer(timer2.stage1_ticks); + s.integer(timer2.stage2_ticks); + s.integer(timer2.stage3_ticks); + s.integer(timer2.current_line); + s.integer(timer2.enable); + s.integer(timer2.target); +} + +#endif diff --git a/snes/smp/smp.cpp b/snes/smp/smp.cpp new file mode 100755 index 00000000..c9419300 --- /dev/null +++ b/snes/smp/smp.cpp @@ -0,0 +1,133 @@ +#include + +#define SMP_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + SMPDebugger smp; +#else + SMP smp; +#endif + +#include "serialization.cpp" +#include "iplrom.cpp" +#include "memory/memory.cpp" +#include "timing/timing.cpp" + +void SMP::step(unsigned clocks) { + clock += clocks * (uint64)cpu.frequency; + dsp.clock -= clocks; +} + +void SMP::synchronize_cpu() { + if(CPU::Threaded == true) { + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +} + +void SMP::synchronize_dsp() { + if(DSP::Threaded == true) { + if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread); + } else { + while(dsp.clock < 0) dsp.enter(); + } +} + +void SMP::Enter() { smp.enter(); } + +void SMP::enter() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + op_step(); + } +} + +void SMP::op_step() { + (this->*opcode_table[op_readpc()])(); +} + +void SMP::power() { + //targets not initialized/changed upon reset + timer0.target = 0; + timer1.target = 0; + timer2.target = 0; + + reset(); +} + +void SMP::reset() { + create(Enter, system.apu_frequency()); + + regs.pc = 0xffc0; + regs.a = 0x00; + regs.x = 0x00; + regs.y = 0x00; + regs.sp = 0xef; + regs.p = 0x02; + + for(auto &n : apuram) n = random(0x00); + apuram[0x00f4] = 0x00; + apuram[0x00f5] = 0x00; + apuram[0x00f6] = 0x00; + apuram[0x00f7] = 0x00; + + status.clock_counter = 0; + status.dsp_counter = 0; + status.timer_step = 3; + + //$00f0 + status.clock_speed = 0; + status.timer_speed = 0; + status.timers_enable = true; + status.ram_disable = false; + status.ram_writable = true; + status.timers_disable = false; + + //$00f1 + status.iplrom_enable = true; + + //$00f2 + status.dsp_addr = 0x00; + + //$00f8,$00f9 + status.ram00f8 = 0x00; + status.ram00f9 = 0x00; + + timer0.stage0_ticks = 0; + timer1.stage0_ticks = 0; + timer2.stage0_ticks = 0; + + timer0.stage1_ticks = 0; + timer1.stage1_ticks = 0; + timer2.stage1_ticks = 0; + + timer0.stage2_ticks = 0; + timer1.stage2_ticks = 0; + timer2.stage2_ticks = 0; + + timer0.stage3_ticks = 0; + timer1.stage3_ticks = 0; + timer2.stage3_ticks = 0; + + timer0.current_line = 0; + timer1.current_line = 0; + timer2.current_line = 0; + + timer0.enable = false; + timer1.enable = false; + timer2.enable = false; +} + +SMP::SMP() { +} + +SMP::~SMP() { +} + +} diff --git a/snes/smp/smp.hpp b/snes/smp/smp.hpp new file mode 100755 index 00000000..5c2d9904 --- /dev/null +++ b/snes/smp/smp.hpp @@ -0,0 +1,62 @@ +struct SMP : public Processor, public SMPcore { + static const uint8 iplrom[64]; + uint8 apuram[64 * 1024]; + + enum : bool { Threaded = true }; + alwaysinline void step(unsigned clocks); + alwaysinline void synchronize_cpu(); + alwaysinline void synchronize_dsp(); + + uint8 port_read(uint2 port) const; + void port_write(uint2 port, uint8 data); + + void enter(); + void power(); + void reset(); + + void serialize(serializer&); + SMP(); + ~SMP(); + +private: + #include "memory/memory.hpp" + #include "timing/timing.hpp" + + struct { + //timing + unsigned clock_counter; + unsigned dsp_counter; + unsigned timer_step; + + //$00f0 + uint8 clock_speed; + uint8 timer_speed; + bool timers_enable; + bool ram_disable; + bool ram_writable; + bool timers_disable; + + //$00f1 + bool iplrom_enable; + + //$00f2 + uint8 dsp_addr; + + //$00f8,$00f9 + uint8 ram00f8; + uint8 ram00f9; + } status; + + static void Enter(); + debugvirtual void op_step(); + + friend class SMPcore; + friend class SMPDebugger; +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern SMPDebugger smp; +#else + extern SMP smp; +#endif diff --git a/snes/smp/timing/timing.cpp b/snes/smp/timing/timing.cpp new file mode 100755 index 00000000..40374d1c --- /dev/null +++ b/snes/smp/timing/timing.cpp @@ -0,0 +1,58 @@ +#ifdef SMP_CPP + +void SMP::add_clocks(unsigned clocks) { + step(clocks); + synchronize_dsp(); + + //forcefully sync S-SMP to S-CPU in case chips are not communicating + //sync if S-SMP is more than 24 samples ahead of S-CPU + if(clock > +(768 * 24 * (int64)24000000)) synchronize_cpu(); +} + +void SMP::cycle_edge() { + timer0.tick(); + timer1.tick(); + timer2.tick(); + + //TEST register S-SMP speed control + //24 clocks have already been added for this cycle at this point + switch(status.clock_speed) { + case 0: break; //100% speed + case 1: add_clocks(24); break; // 50% speed + case 2: while(true) add_clocks(24); // 0% speed -- locks S-SMP + case 3: add_clocks(24 * 9); break; // 10% speed + } +} + +template +void SMP::Timer::tick() { + //stage 0 increment + stage0_ticks += smp.status.timer_step; + if(stage0_ticks < timer_frequency) return; + stage0_ticks -= timer_frequency; + + //stage 1 increment + stage1_ticks ^= 1; + synchronize_stage1(); +} + +template +void SMP::Timer::synchronize_stage1() { + bool new_line = stage1_ticks; + if(smp.status.timers_enable == false) new_line = false; + if(smp.status.timers_disable == true) new_line = false; + + bool old_line = current_line; + current_line = new_line; + if(old_line != 1 || new_line != 0) return; //only pulse on 1->0 transition + + //stage 2 increment + if(enable == false) return; + if(++stage2_ticks != target) return; + + //stage 3 increment + stage2_ticks = 0; + stage3_ticks++; +} + +#endif diff --git a/snes/smp/timing/timing.hpp b/snes/smp/timing/timing.hpp new file mode 100755 index 00000000..2c282455 --- /dev/null +++ b/snes/smp/timing/timing.hpp @@ -0,0 +1,21 @@ +template +class Timer { +public: + uint8 stage0_ticks; + uint8 stage1_ticks; + uint8 stage2_ticks; + uint4 stage3_ticks; + bool current_line; + bool enable; + uint8 target; + + void tick(); + void synchronize_stage1(); +}; + +Timer<192> timer0; +Timer<192> timer1; +Timer< 24> timer2; + +alwaysinline void add_clocks(unsigned clocks); +alwaysinline void cycle_edge(); diff --git a/snes/snes.hpp b/snes/snes.hpp new file mode 100755 index 00000000..91196f9e --- /dev/null +++ b/snes/snes.hpp @@ -0,0 +1,159 @@ +#ifndef SNES_HPP +#define SNES_HPP + +namespace SNES { + namespace Info { + static const char Name[] = "bsnes"; + static const unsigned SerializerVersion = 22; + } +} + +/* + bsnes - SNES emulator + author: byuu + license: GPLv3 + project started: 2004-10-14 +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace nall; + +#include + +#ifdef DEBUGGER + #define debugvirtual virtual +#else + #define debugvirtual +#endif + +namespace SNES { + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + + typedef int_t<24> int24; + + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + + typedef uint_t< 1> uint1; + typedef uint_t< 2> uint2; + typedef uint_t< 3> uint3; + typedef uint_t< 4> uint4; + typedef uint_t< 5> uint5; + typedef uint_t< 6> uint6; + typedef uint_t< 7> uint7; + + typedef uint_t< 9> uint9; + typedef uint_t<10> uint10; + typedef uint_t<11> uint11; + typedef uint_t<12> uint12; + typedef uint_t<13> uint13; + typedef uint_t<14> uint14; + typedef uint_t<15> uint15; + + typedef uint_t<17> uint17; + typedef uint_t<18> uint18; + typedef uint_t<19> uint19; + typedef uint_t<20> uint20; + typedef uint_t<21> uint21; + typedef uint_t<22> uint22; + typedef uint_t<23> uint23; + typedef uint_t<24> uint24; + typedef uint_t<25> uint25; + typedef uint_t<26> uint26; + typedef uint_t<27> uint27; + typedef uint_t<28> uint28; + typedef uint_t<29> uint29; + typedef uint_t<30> uint30; + typedef uint_t<31> uint31; + + typedef varuint_t varuint; + + template + alwaysinline bool within(unsigned addr) { + static const unsigned lo = (banklo << 16) | addrlo; + static const unsigned hi = (bankhi << 16) | addrhi; + static const unsigned mask = ~(hi ^ lo); + return (addr & mask) == lo; + } + + struct Processor { + cothread_t thread; + unsigned frequency; + int64 clock; + + inline void create(void (*entrypoint)(), unsigned frequency) { + if(thread) co_delete(thread); + thread = co_create(65536 * sizeof(void*), entrypoint); + this->frequency = frequency; + clock = 0; + } + + inline void serialize(serializer &s) { + s.integer(frequency); + s.integer(clock); + } + + inline Processor() : thread(nullptr) { + } + + inline ~Processor() { + if(thread) co_delete(thread); + } + }; + + struct ChipDebugger { + virtual bool property(unsigned id, string &name, string &value) = 0; + }; + + #include + #include + #include + #include + + #if defined(PROFILE_ACCURACY) + #include "profile-accuracy.hpp" + #elif defined(PROFILE_COMPATIBILITY) + #include "profile-compatibility.hpp" + #elif defined(PROFILE_PERFORMANCE) + #include "profile-performance.hpp" + #endif + + #include + #include + #include + #include + #include + #include + + #include + #include +} + +#undef debugvirtual + +#endif diff --git a/snes/system/serialization.cpp b/snes/system/serialization.cpp new file mode 100755 index 00000000..f7d6f3b1 --- /dev/null +++ b/snes/system/serialization.cpp @@ -0,0 +1,92 @@ +#ifdef SYSTEM_CPP + +serializer System::serialize() { + serializer s(serialize_size); + + unsigned signature = 0x31545342, version = Info::SerializerVersion, crc32 = cartridge.crc32(); + char description[512], profile[16]; + memset(&description, 0, sizeof description); + memset(&profile, 0, sizeof profile); + strlcpy(profile, Info::Profile, sizeof profile); + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(description); + s.array(profile); + + serialize_all(s); + return s; +} + +bool System::unserialize(serializer &s) { + unsigned signature, version, crc32; + char description[512], profile[16]; + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(description); + s.array(profile); + + if(signature != 0x31545342) return false; + if(version != Info::SerializerVersion) return false; +//if(crc32 != cartridge.crc32()) return false; + if(strcmp(profile, Info::Profile)) return false; + + power(); + serialize_all(s); + return true; +} + +//======== +//internal +//======== + +void System::serialize(serializer &s) { + s.integer((unsigned&)region); + s.integer((unsigned&)expansion); +} + +void System::serialize_all(serializer &s) { + cartridge.serialize(s); + system.serialize(s); + random.serialize(s); + cpu.serialize(s); + smp.serialize(s); + ppu.serialize(s); + dsp.serialize(s); + + if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s); + if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s); + if(cartridge.has_superfx()) superfx.serialize(s); + if(cartridge.has_sa1()) sa1.serialize(s); + if(cartridge.has_necdsp()) necdsp.serialize(s); + if(cartridge.has_hitachidsp()) hitachidsp.serialize(s); + if(cartridge.has_srtc()) srtc.serialize(s); + if(cartridge.has_sdd1()) sdd1.serialize(s); + if(cartridge.has_spc7110()) spc7110.serialize(s); + if(cartridge.has_obc1()) obc1.serialize(s); + if(cartridge.has_msu1()) msu1.serialize(s); +} + +//perform dry-run state save: +//determines exactly how many bytes are needed to save state for this cartridge, +//as amount varies per game (eg different RAM sizes, special chips, etc.) +void System::serialize_init() { + serializer s; + + unsigned signature = 0, version = 0, crc32 = 0; + char profile[16], description[512]; + + s.integer(signature); + s.integer(version); + s.integer(crc32); + s.array(profile); + s.array(description); + + serialize_all(s); + serialize_size = s.size(); +} + +#endif diff --git a/snes/system/system.cpp b/snes/system/system.cpp new file mode 100755 index 00000000..68818109 --- /dev/null +++ b/snes/system/system.cpp @@ -0,0 +1,248 @@ +#include + +#define SYSTEM_CPP +namespace SNES { + +System system; + +#include +#include +#include +#include + +#include +#include +#include + +#include "serialization.cpp" + +void System::run() { + scheduler.sync = Scheduler::SynchronizeMode::None; + + scheduler.enter(); + if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) { + video.update(); + } +} + +void System::runtosave() { + if(CPU::Threaded == true) { + scheduler.sync = Scheduler::SynchronizeMode::CPU; + runthreadtosave(); + } + + if(SMP::Threaded == true) { + scheduler.thread = smp.thread; + runthreadtosave(); + } + + if(PPU::Threaded == true) { + scheduler.thread = ppu.thread; + runthreadtosave(); + } + + if(DSP::Threaded == true) { + scheduler.thread = dsp.thread; + runthreadtosave(); + } + + for(unsigned i = 0; i < cpu.coprocessors.size(); i++) { + Processor &chip = *cpu.coprocessors[i]; + scheduler.thread = chip.thread; + runthreadtosave(); + } +} + +void System::runthreadtosave() { + while(true) { + scheduler.enter(); + if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break; + if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) { + video.update(); + } + } +} + +void System::init() { + assert(interface != 0); + + icd2.init(); + nss.init(); + superfx.init(); + sa1.init(); + necdsp.init(); + hitachidsp.init(); + bsxsatellaview.init(); + bsxcartridge.init(); + bsxflash.init(); + srtc.init(); + sdd1.init(); + spc7110.init(); + obc1.init(); + st0018.init(); + msu1.init(); + link.init(); + + video.init(); + audio.init(); + + input.connect(0, config.controller_port1); + input.connect(1, config.controller_port2); +} + +void System::term() { +} + +void System::load() { + audio.coprocessor_enable(false); + + bus.map_reset(); + bus.map_xml(); + + cpu.enable(); + ppu.enable(); + + if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.load(); + if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.load(); + if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.load(); + if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.load(); + + if(cartridge.has_bsx_slot()) bsxflash.load(); + if(cartridge.has_nss_dip()) nss.load(); + if(cartridge.has_superfx()) superfx.load(); + if(cartridge.has_sa1()) sa1.load(); + if(cartridge.has_necdsp()) necdsp.load(); + if(cartridge.has_hitachidsp()) hitachidsp.load(); + if(cartridge.has_srtc()) srtc.load(); + if(cartridge.has_sdd1()) sdd1.load(); + if(cartridge.has_spc7110()) spc7110.load(); + if(cartridge.has_obc1()) obc1.load(); + if(cartridge.has_st0018()) st0018.load(); + if(cartridge.has_msu1()) msu1.load(); + if(cartridge.has_link()) link.load(); + + serialize_init(); + cheat.init(); +} + +void System::unload() { + if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.unload(); + if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.unload(); + if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.unload(); + if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.unload(); + + if(cartridge.has_bsx_slot()) bsxflash.unload(); + if(cartridge.has_nss_dip()) nss.unload(); + if(cartridge.has_superfx()) superfx.unload(); + if(cartridge.has_sa1()) sa1.unload(); + if(cartridge.has_necdsp()) necdsp.unload(); + if(cartridge.has_hitachidsp()) hitachidsp.unload(); + if(cartridge.has_srtc()) srtc.unload(); + if(cartridge.has_sdd1()) sdd1.unload(); + if(cartridge.has_spc7110()) spc7110.unload(); + if(cartridge.has_obc1()) obc1.unload(); + if(cartridge.has_st0018()) st0018.unload(); + if(cartridge.has_msu1()) msu1.unload(); + if(cartridge.has_link()) link.unload(); +} + +void System::power() { + random.seed((unsigned)time(0)); + + region = config.region; + expansion = config.expansion_port; + if(region == Region::Autodetect) { + region = (cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL); + } + + cpu_frequency = region() == Region::NTSC ? config.cpu.ntsc_frequency : config.cpu.pal_frequency; + apu_frequency = region() == Region::NTSC ? config.smp.ntsc_frequency : config.smp.pal_frequency; + + cpu.power(); + smp.power(); + dsp.power(); + ppu.power(); + + if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.power(); + if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.power(); + if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.power(); + + if(cartridge.has_bsx_slot()) bsxflash.power(); + if(cartridge.has_nss_dip()) nss.power(); + if(cartridge.has_superfx()) superfx.power(); + if(cartridge.has_sa1()) sa1.power(); + if(cartridge.has_necdsp()) necdsp.power(); + if(cartridge.has_hitachidsp()) hitachidsp.power(); + if(cartridge.has_srtc()) srtc.power(); + if(cartridge.has_sdd1()) sdd1.power(); + if(cartridge.has_spc7110()) spc7110.power(); + if(cartridge.has_obc1()) obc1.power(); + if(cartridge.has_st0018()) st0018.power(); + if(cartridge.has_msu1()) msu1.power(); + if(cartridge.has_link()) link.power(); + + if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2); + if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx); + if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1); + 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_link()) cpu.coprocessors.append(&link); + + scheduler.init(); + input.connect(0, config.controller_port1); + input.connect(1, config.controller_port2); +} + +void System::reset() { + cpu.reset(); + smp.reset(); + dsp.reset(); + ppu.reset(); + + if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.reset(); + + if(cartridge.mode() == Cartridge::Mode::Bsx) bsxcartridge.reset(); + if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.reset(); + + if(cartridge.has_bsx_slot()) bsxflash.reset(); + if(cartridge.has_nss_dip()) nss.reset(); + if(cartridge.has_superfx()) superfx.reset(); + if(cartridge.has_sa1()) sa1.reset(); + if(cartridge.has_necdsp()) necdsp.reset(); + if(cartridge.has_hitachidsp()) hitachidsp.reset(); + if(cartridge.has_srtc()) srtc.reset(); + if(cartridge.has_sdd1()) sdd1.reset(); + if(cartridge.has_spc7110()) spc7110.reset(); + if(cartridge.has_obc1()) obc1.reset(); + if(cartridge.has_st0018()) st0018.reset(); + if(cartridge.has_msu1()) msu1.reset(); + if(cartridge.has_link()) link.reset(); + + if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2); + if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx); + if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1); + 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_link()) cpu.coprocessors.append(&link); + + scheduler.init(); + input.connect(0, config.controller_port1); + input.connect(1, config.controller_port2); +} + +void System::scanline() { + video.scanline(); + if(cpu.vcounter() == 241) scheduler.exit(Scheduler::ExitReason::FrameEvent); +} + +void System::frame() { +} + +System::System() { + region = Region::Autodetect; + expansion = ExpansionPortDevice::BSX; +} + +} diff --git a/snes/system/system.hpp b/snes/system/system.hpp new file mode 100755 index 00000000..3d8d6e77 --- /dev/null +++ b/snes/system/system.hpp @@ -0,0 +1,54 @@ +struct Interface; + +struct System : property { + enum class Region : unsigned { NTSC = 0, PAL = 1, Autodetect = 2 }; + enum class ExpansionPortDevice : unsigned { None = 0, BSX = 1 }; + + void run(); + void runtosave(); + + void init(); + void term(); + void load(); + void unload(); + void power(); + void reset(); + + void frame(); + void scanline(); + + //return *active* system information (settings are cached upon power-on) + readonly region; + readonly expansion; + readonly cpu_frequency; + readonly apu_frequency; + readonly serialize_size; + + serializer serialize(); + bool unserialize(serializer&); + + System(); + +private: + void runthreadtosave(); + + void serialize(serializer&); + void serialize_all(serializer&); + void serialize_init(); + + friend class Cartridge; + friend class Video; + friend class Audio; + friend class Input; +}; + +#include +#include +#include + +#include +#include +#include +#include + +extern System system; diff --git a/snes/video/video.cpp b/snes/video/video.cpp new file mode 100755 index 00000000..9666f194 --- /dev/null +++ b/snes/video/video.cpp @@ -0,0 +1,150 @@ +#ifdef SYSTEM_CPP + +Video video; + +unsigned Video::palette30(unsigned color) { + unsigned l = (color >> 15) & 15; + unsigned b = (color >> 10) & 31; + unsigned g = (color >> 5) & 31; + unsigned r = (color >> 0) & 31; + + double L = (1.0 + l) / 16.0; + unsigned R = L * ((r << 5) + (r << 0)); + unsigned G = L * ((g << 5) + (g << 0)); + unsigned B = L * ((b << 5) + (b << 0)); + + return (R << 20) + (G << 10) + (B << 0); +} + +void Video::generate(Format format) { + for(unsigned n = 0; n < (1 << 19); n++) palette[n] = palette30(n); + + if(format == Format::RGB24) { + for(unsigned n = 0; n < (1 << 19); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff); + } + } + + if(format == Format::RGB16) { + for(unsigned n = 0; n < (1 << 19); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f); + } + } + + if(format == Format::RGB15) { + for(unsigned n = 0; n < (1 << 19); n++) { + unsigned color = palette[n]; + palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f); + } + } +} + +Video::Video() { + palette = new unsigned[1 << 19]; +} + +Video::~Video() { + delete[] palette; +} + +//internal + +const uint8_t Video::cursor[15 * 15] = { + 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, + 0,0,0,0,1,1,2,2,2,1,1,0,0,0,0, + 0,0,0,1,2,2,1,2,1,2,2,1,0,0,0, + 0,0,1,2,1,1,0,1,0,1,1,2,1,0,0, + 0,1,2,1,0,0,0,1,0,0,0,1,2,1,0, + 0,1,2,1,0,0,1,2,1,0,0,1,2,1,0, + 1,2,1,0,0,1,1,2,1,1,0,0,1,2,1, + 1,2,2,1,1,2,2,2,2,2,1,1,2,2,1, + 1,2,1,0,0,1,1,2,1,1,0,0,1,2,1, + 0,1,2,1,0,0,1,2,1,0,0,1,2,1,0, + 0,1,2,1,0,0,0,1,0,0,0,1,2,1,0, + 0,0,1,2,1,1,0,1,0,1,1,2,1,0,0, + 0,0,0,1,2,2,1,2,1,2,2,1,0,0,0, + 0,0,0,0,1,1,2,2,2,1,1,0,0,0,0, + 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0, +}; + +void Video::draw_cursor(uint16_t color, int x, int y) { + uint32_t *data = (uint32_t*)ppu.output; + if(ppu.interlace() && ppu.field()) data += 512; + + for(int cy = 0; cy < 15; cy++) { + int vy = y + cy - 7; + if(vy <= 0 || vy >= 240) continue; //do not draw offscreen + + bool hires = (line_width[vy] == 512); + for(int cx = 0; cx < 15; cx++) { + int vx = x + cx - 7; + if(vx < 0 || vx >= 256) continue; //do not draw offscreen + uint8_t pixel = cursor[cy * 15 + cx]; + if(pixel == 0) continue; + uint32_t pixelcolor = (15 << 15) | ((pixel == 1) ? 0 : color); + + if(hires == false) { + *((uint32_t*)data + vy * 1024 + vx) = pixelcolor; + } else { + *((uint32_t*)data + vy * 1024 + vx * 2 + 0) = pixelcolor; + *((uint32_t*)data + vy * 1024 + vx * 2 + 1) = pixelcolor; + } + } + } +} + +void Video::update() { + switch(config.controller_port2) { + 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; + } + + uint32_t *data = (uint32_t*)ppu.output; + if(ppu.interlace() && ppu.field()) data += 512; + + if(hires) { + //normalize line widths + for(unsigned y = 0; y < 240; y++) { + if(line_width[y] == 512) continue; + uint32_t *buffer = data + y * 1024; + for(signed x = 255; x >= 0; x--) { + buffer[(x * 2) + 0] = buffer[(x * 2) + 1] = buffer[x]; + } + } + } + + interface->videoRefresh(ppu.surface, hires, ppu.interlace(), ppu.overscan()); + + hires = false; +} + +void Video::scanline() { + unsigned y = cpu.vcounter(); + if(y >= 240) return; + + hires |= ppu.hires(); + unsigned width = (ppu.hires() == false ? 256 : 512); + line_width[y] = width; +} + +void Video::init() { + hires = false; + for(auto &n : line_width) n = 256; +} + +#endif diff --git a/snes/video/video.hpp b/snes/video/video.hpp new file mode 100755 index 00000000..f01cac65 --- /dev/null +++ b/snes/video/video.hpp @@ -0,0 +1,24 @@ +struct Video { + enum class Format : unsigned { RGB30, RGB24, RGB16, RGB15 }; + unsigned *palette; + + unsigned palette30(unsigned color); + void generate(Format format); + Video(); + ~Video(); + +private: + bool hires; + unsigned line_width[240]; + + void update(); + void scanline(); + void init(); + + static const uint8_t cursor[15 * 15]; + void draw_cursor(uint16_t color, int x, int y); + + friend class System; +}; + +extern Video video; diff --git a/sync.sh b/sync.sh new file mode 100755 index 00000000..abb2b37b --- /dev/null +++ b/sync.sh @@ -0,0 +1,18 @@ +synchronize() { + if [ -d ../"$1" ]; then + test -d "$1" && rm -r "$1" + cp -r ../"$1" ./"$1" + fi +} + +synchronize "libco" +synchronize "nall" +synchronize "ruby" +synchronize "phoenix" + +test -d libco/doc && rm -r libco/doc +test -d libco/test && rm -r libco/test +test -d nall/test && rm -r nall/test +test -d ruby/_test && rm -r ruby/_test +test -d phoenix/nall && rm -r phoenix/nall +test -d phoenix/test && rm -r phoenix/test diff --git a/ui-libsnes/Makefile b/ui-libsnes/Makefile new file mode 100755 index 00000000..378bcfff --- /dev/null +++ b/ui-libsnes/Makefile @@ -0,0 +1,45 @@ +include $(snes)/Makefile +include $(gameboy)/Makefile +output := libsnes + +ifeq ($(platform),x) + flags += -fPIC +else ifeq ($(platform),osx) + flags += -fPIC +else ifeq ($(platform),win) +endif + +#rules +objects := $(objects) libsnes +objects := $(patsubst %,obj/%.o,$(objects)) + +obj/libsnes.o: $(ui)/libsnes.cpp $(ui)/* + +#targets +build: $(objects) +ifeq ($(platform),x) + ar rcs out/libsnes.a $(objects) + $(cpp) -o out/libsnes.so -shared -Wl,-soname,libsnes.so.1 $(objects) +else ifeq ($(platform),osx) + ar rcs out/libsnes.a $(objects) + $(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(objects) +else ifeq ($(platform),win) + $(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(objects) +endif + +install: +ifeq ($(platform),x) + install -D -m 755 out/libsnes.a $(DESTDIR)$(prefix)/lib/libsnes.a + install -D -m 755 out/libsnes.so $(DESTDIR)$(prefix)/lib/libsnes.so + ldconfig -n $(DESTDIR)$(prefix)/lib +else ifeq ($(platform),osx) + cp out/libsnes.dylib /usr/local/lib/libsnes.dylib +endif + +uninstall: +ifeq ($(platform),x) + rm $(DESTDIR)$(prefix)/lib/libsnes.a + rm $(DESTDIR)$(prefix)/lib/libsnes.so +else ifeq ($(platform),osx) + rm /usr/local/lib/libsnes.dylib +endif diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp new file mode 100755 index 00000000..fbb4482c --- /dev/null +++ b/ui-libsnes/libsnes.cpp @@ -0,0 +1,362 @@ +#include "libsnes.hpp" +#include + +#include +#include +using namespace nall; + +struct Interface : public SNES::Interface { + snes_video_refresh_t pvideo_refresh; + snes_audio_sample_t paudio_sample; + snes_input_poll_t pinput_poll; + snes_input_state_t pinput_state; + string basename; + uint16_t *buffer; + uint32_t *palette; + + void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) { + unsigned width = hires ? 512 : 256; + unsigned height = overscan ? 239 : 224; + unsigned pitch = 1024 >> interlace; + if(interlace) height <<= 1; + data += 9 * 1024; //skip front porch + + for(unsigned y = 0; y < height; y++) { + const uint32_t *sp = data + y * pitch; + uint16_t *dp = buffer + y * pitch; + for(unsigned x = 0; x < width; x++) { + *dp++ = palette[*sp++]; + } + } + + if(pvideo_refresh) pvideo_refresh(buffer, width, height); + if(pinput_poll) pinput_poll(); + } + + void audioSample(int16_t left, int16_t right) { + if(paudio_sample) return paudio_sample(left, right); + } + + int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) { + if(pinput_state) return pinput_state(port, (unsigned)device, index, id); + return 0; + } + + void message(const string &text) { + print(text, "\n"); + } + + string path(SNES::Cartridge::Slot slot, const string &hint) { + return { basename, hint }; + } + + Interface() : pvideo_refresh(0), paudio_sample(0), pinput_poll(0), pinput_state(0) { + buffer = new uint16_t[512 * 480]; + palette = new uint32_t[16 * 32768]; + + //{llll bbbbb ggggg rrrrr} -> { rrrrr ggggg bbbbb } + for(unsigned l = 0; l < 16; l++) { + for(unsigned r = 0; r < 32; r++) { + for(unsigned g = 0; g < 32; g++) { + for(unsigned b = 0; b < 32; b++) { + double luma = (double)l / 15.0; + unsigned ar = (luma * r + 0.5); + unsigned ag = (luma * g + 0.5); + unsigned ab = (luma * b + 0.5); + palette[(l << 15) + (r << 10) + (g << 5) + (b << 0)] = (ab << 10) + (ag << 5) + (ar << 0); + } + } + } + } + } + + ~Interface() { + delete[] buffer; + delete[] palette; + } +}; + +static Interface interface; + +const char* snes_library_id(void) { + return "bsnes v083"; +} + +unsigned snes_library_revision_major(void) { + return 1; +} + +unsigned snes_library_revision_minor(void) { + return 3; +} + +void snes_set_video_refresh(snes_video_refresh_t video_refresh) { + interface.pvideo_refresh = video_refresh; +} + +void snes_set_audio_sample(snes_audio_sample_t audio_sample) { + interface.paudio_sample = audio_sample; +} + +void snes_set_input_poll(snes_input_poll_t input_poll) { + interface.pinput_poll = input_poll; +} + +void snes_set_input_state(snes_input_state_t input_state) { + interface.pinput_state = input_state; +} + +void snes_set_controller_port_device(bool port, unsigned device) { + SNES::input.connect(port, (SNES::Input::Device)device); +} + +void snes_set_cartridge_basename(const char *basename) { + interface.basename = basename; +} + +void snes_init(void) { + interface.initialize(&interface); + SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad); + SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad); +} + +void snes_term(void) { + SNES::system.term(); +} + +void snes_power(void) { + SNES::system.power(); +} + +void snes_reset(void) { + SNES::system.reset(); +} + +void snes_run(void) { + SNES::system.run(); +} + +unsigned snes_serialize_size(void) { + return SNES::system.serialize_size(); +} + +bool snes_serialize(uint8_t *data, unsigned size) { + SNES::system.runtosave(); + serializer s = SNES::system.serialize(); + if(s.size() > size) return false; + memcpy(data, s.data(), s.size()); + return true; +} + +bool snes_unserialize(const uint8_t *data, unsigned size) { + serializer s(data, size); + return SNES::system.unserialize(s); +} + +struct CheatList { + bool enable; + string code; + CheatList() : enable(false) {} +}; + +static linear_vector cheatList; + +void snes_cheat_reset(void) { + cheatList.reset(); + interface.setCheats(); +} + +void snes_cheat_set(unsigned index, bool enable, const char *code) { + cheatList[index].enable = enable; + cheatList[index].code = code; + lstring list; + for(unsigned n = 0; n < cheatList.size(); n++) { + if(cheatList[n].enable) list.append(cheatList[n].code); + } + interface.setCheats(list); +} + +bool snes_load_cartridge_normal( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size +) { + snes_cheat_reset(); + if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); + string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; + SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { xmlrom }); + SNES::system.power(); + return true; +} + +bool snes_load_cartridge_bsx_slotted( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size +) { + snes_cheat_reset(); + if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); + string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; + if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size); + string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SnesCartridge(bsx_data, bsx_size).markup; + SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, xmlrom); + SNES::system.power(); + return true; +} + +bool snes_load_cartridge_bsx( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size +) { + snes_cheat_reset(); + if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); + string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; + if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size); + string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SnesCartridge(bsx_data, bsx_size).markup; + SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, xmlrom); + SNES::system.power(); + return true; +} + +bool snes_load_cartridge_sufami_turbo( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *sta_xml, const uint8_t *sta_data, unsigned sta_size, + const char *stb_xml, const uint8_t *stb_data, unsigned stb_size +) { + snes_cheat_reset(); + if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); + string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; + if(sta_data) SNES::sufamiturbo.slotA.rom.copy(sta_data, sta_size); + string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : SnesCartridge(sta_data, sta_size).markup; + if(stb_data) SNES::sufamiturbo.slotB.rom.copy(stb_data, stb_size); + string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : SnesCartridge(stb_data, stb_size).markup; + SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, xmlrom); + SNES::system.power(); + return true; +} + +bool snes_load_cartridge_super_game_boy( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size +) { + snes_cheat_reset(); + if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); + string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; + if(dmg_data) { + //GameBoyCartridge needs to modify dmg_data (for MMM01 emulation); so copy data + uint8_t *data = new uint8_t[dmg_size]; + memcpy(data, dmg_data, dmg_size); + string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(data, dmg_size).markup; + GameBoy::cartridge.load(xmldmg, data, dmg_size); + delete[] data; + } + SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom); + SNES::system.power(); + return true; +} + +void snes_unload_cartridge(void) { + SNES::cartridge.unload(); +} + +bool snes_get_region(void) { + return SNES::system.region() == SNES::System::Region::NTSC ? 0 : 1; +} + +uint8_t* snes_get_memory_data(unsigned id) { + if(SNES::cartridge.loaded() == false) return 0; + + switch(id) { + case SNES_MEMORY_CARTRIDGE_RAM: + return SNES::cartridge.ram.data(); + case SNES_MEMORY_CARTRIDGE_RTC: + if(SNES::cartridge.has_srtc()) return SNES::srtc.rtc; + if(SNES::cartridge.has_spc7110rtc()) return SNES::spc7110.rtc; + return 0; + case SNES_MEMORY_BSX_RAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; + return SNES::bsxcartridge.sram.data(); + case SNES_MEMORY_BSX_PRAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; + return SNES::bsxcartridge.psram.data(); + case SNES_MEMORY_SUFAMI_TURBO_A_RAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; + return SNES::sufamiturbo.slotA.ram.data(); + case SNES_MEMORY_SUFAMI_TURBO_B_RAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; + return SNES::sufamiturbo.slotB.ram.data(); + case SNES_MEMORY_GAME_BOY_RAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; + return GameBoy::cartridge.ramdata; + //case SNES_MEMORY_GAME_BOY_RTC: + // if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; + // return GameBoy::cartridge.rtcdata; + + case SNES_MEMORY_WRAM: + return SNES::cpu.wram; + case SNES_MEMORY_APURAM: + return SNES::smp.apuram; + case SNES_MEMORY_VRAM: + return SNES::ppu.vram; + case SNES_MEMORY_OAM: + return SNES::ppu.oam; + case SNES_MEMORY_CGRAM: + return SNES::ppu.cgram; + } + + return 0; +} + +unsigned snes_get_memory_size(unsigned id) { + if(SNES::cartridge.loaded() == false) return 0; + unsigned size = 0; + + switch(id) { + case SNES_MEMORY_CARTRIDGE_RAM: + size = SNES::cartridge.ram.size(); + break; + case SNES_MEMORY_CARTRIDGE_RTC: + if(SNES::cartridge.has_srtc() || SNES::cartridge.has_spc7110rtc()) size = 20; + break; + case SNES_MEMORY_BSX_RAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; + size = SNES::bsxcartridge.sram.size(); + break; + case SNES_MEMORY_BSX_PRAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; + size = SNES::bsxcartridge.psram.size(); + break; + case SNES_MEMORY_SUFAMI_TURBO_A_RAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; + size = SNES::sufamiturbo.slotA.ram.size(); + break; + case SNES_MEMORY_SUFAMI_TURBO_B_RAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; + size = SNES::sufamiturbo.slotB.ram.size(); + break; + case SNES_MEMORY_GAME_BOY_RAM: + if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; + size = GameBoy::cartridge.ramsize; + break; + //case SNES_MEMORY_GAME_BOY_RTC: + // if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; + // size = GameBoy::cartridge.rtcsize; + // break; + + case SNES_MEMORY_WRAM: + size = 128 * 1024; + break; + case SNES_MEMORY_APURAM: + size = 64 * 1024; + break; + case SNES_MEMORY_VRAM: + size = 64 * 1024; + break; + case SNES_MEMORY_OAM: + size = 544; + break; + case SNES_MEMORY_CGRAM: + size = 512; + break; + } + + if(size == -1U) size = 0; + return size; +} diff --git a/ui-libsnes/libsnes.hpp b/ui-libsnes/libsnes.hpp new file mode 100755 index 00000000..18b269f1 --- /dev/null +++ b/ui-libsnes/libsnes.hpp @@ -0,0 +1,135 @@ +#ifndef LIBSNES_HPP +#define LIBSNES_HPP + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#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_SERIAL_CABLE 7 + +#define SNES_DEVICE_ID_JOYPAD_B 0 +#define SNES_DEVICE_ID_JOYPAD_Y 1 +#define SNES_DEVICE_ID_JOYPAD_SELECT 2 +#define SNES_DEVICE_ID_JOYPAD_START 3 +#define SNES_DEVICE_ID_JOYPAD_UP 4 +#define SNES_DEVICE_ID_JOYPAD_DOWN 5 +#define SNES_DEVICE_ID_JOYPAD_LEFT 6 +#define SNES_DEVICE_ID_JOYPAD_RIGHT 7 +#define SNES_DEVICE_ID_JOYPAD_A 8 +#define SNES_DEVICE_ID_JOYPAD_X 9 +#define SNES_DEVICE_ID_JOYPAD_L 10 +#define SNES_DEVICE_ID_JOYPAD_R 11 + +#define SNES_DEVICE_ID_MOUSE_X 0 +#define SNES_DEVICE_ID_MOUSE_Y 1 +#define SNES_DEVICE_ID_MOUSE_LEFT 2 +#define SNES_DEVICE_ID_MOUSE_RIGHT 3 + +#define SNES_DEVICE_ID_SUPER_SCOPE_X 0 +#define SNES_DEVICE_ID_SUPER_SCOPE_Y 1 +#define SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER 2 +#define SNES_DEVICE_ID_SUPER_SCOPE_CURSOR 3 +#define SNES_DEVICE_ID_SUPER_SCOPE_TURBO 4 +#define SNES_DEVICE_ID_SUPER_SCOPE_PAUSE 5 + +#define SNES_DEVICE_ID_JUSTIFIER_X 0 +#define SNES_DEVICE_ID_JUSTIFIER_Y 1 +#define SNES_DEVICE_ID_JUSTIFIER_TRIGGER 2 +#define SNES_DEVICE_ID_JUSTIFIER_START 3 + +#define SNES_REGION_NTSC 0 +#define SNES_REGION_PAL 1 + +#define SNES_MEMORY_CARTRIDGE_RAM 0 +#define SNES_MEMORY_CARTRIDGE_RTC 1 +#define SNES_MEMORY_BSX_RAM 2 +#define SNES_MEMORY_BSX_PRAM 3 +#define SNES_MEMORY_SUFAMI_TURBO_A_RAM 4 +#define SNES_MEMORY_SUFAMI_TURBO_B_RAM 5 +#define SNES_MEMORY_GAME_BOY_RAM 6 +#define SNES_MEMORY_GAME_BOY_RTC 7 + +#define SNES_MEMORY_WRAM 100 +#define SNES_MEMORY_APURAM 101 +#define SNES_MEMORY_VRAM 102 +#define SNES_MEMORY_OAM 103 +#define SNES_MEMORY_CGRAM 104 + +typedef void (*snes_video_refresh_t)(const uint16_t *data, unsigned width, unsigned height); +typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right); +typedef void (*snes_input_poll_t)(void); +typedef int16_t (*snes_input_state_t)(bool port, unsigned device, unsigned index, unsigned id); + +const char* snes_library_id(void); +unsigned snes_library_revision_major(void); +unsigned snes_library_revision_minor(void); + +void snes_set_video_refresh(snes_video_refresh_t); +void snes_set_audio_sample(snes_audio_sample_t); +void snes_set_input_poll(snes_input_poll_t); +void snes_set_input_state(snes_input_state_t); + +void snes_set_controller_port_device(bool port, unsigned device); +void snes_set_cartridge_basename(const char *basename); + +void snes_init(void); +void snes_term(void); +void snes_power(void); +void snes_reset(void); +void snes_run(void); + +unsigned snes_serialize_size(void); +bool snes_serialize(uint8_t *data, unsigned size); +bool snes_unserialize(const uint8_t *data, unsigned size); + +void snes_cheat_reset(void); +void snes_cheat_set(unsigned index, bool enable, const char *code); + +bool snes_load_cartridge_normal( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size +); + +bool snes_load_cartridge_bsx_slotted( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size +); + +bool snes_load_cartridge_bsx( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size +); + +bool snes_load_cartridge_sufami_turbo( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *sta_xml, const uint8_t *sta_data, unsigned sta_size, + const char *stb_xml, const uint8_t *stb_data, unsigned stb_size +); + +bool snes_load_cartridge_super_game_boy( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size +); + +void snes_unload_cartridge(void); + +bool snes_get_region(void); +uint8_t* snes_get_memory_data(unsigned id); +unsigned snes_get_memory_size(unsigned id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ui/Makefile b/ui/Makefile new file mode 100755 index 00000000..846c6ffa --- /dev/null +++ b/ui/Makefile @@ -0,0 +1,92 @@ +include $(nes)/Makefile +include $(snes)/Makefile +include $(gameboy)/Makefile +name := bsnes + +ui_objects := ui-main ui-config ui-interface ui-input ui-utility +ui_objects += ui-window ui-general ui-settings ui-tools +ui_objects += phoenix ruby +ui_objects += $(if $(call streq,$(platform),win),resource) + +# platform +ifeq ($(platform),x) + ifeq ($(phoenix),gtk) + phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`) + link += `pkg-config --libs gtk+-2.0` + else + phoenix_compile = $(call compile,-DPHOENIX_QT `pkg-config --cflags QtCore QtGui`) + link += `pkg-config --libs QtCore QtGui` + endif + + ruby := video.glx video.xv video.sdl + ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao + ruby += input.sdl input.x +else ifeq ($(platform),osx) + phoenix_compile = $(call compile,-DPHOENIX_QT) + link += + + ruby := + ruby += audio.openal + ruby += input.carbon +else ifeq ($(platform),win) + phoenix_compile = $(call compile,-DPHOENIX_WINDOWS) + link += + + ruby := video.direct3d video.wgl video.directdraw video.gdi + ruby += audio.directsound audio.xaudio2 + ruby += input.rawinput input.directinput +endif + +# ruby +include ruby/Makefile +link += $(rubylink) + +# rules +objects := $(ui_objects) $(objects) +objects := $(patsubst %,obj/%.o,$(objects)) + +obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/) +obj/ui-config.o: $(ui)/config/config.cpp $(call rwildcard,$(ui)/) +obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/) +obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/) +obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/) +obj/ui-window.o: $(ui)/window/window.cpp $(call rwildcard,$(ui)/) +obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/) +obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/) +obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/) + +obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*) + $(call compile,$(rubyflags)) + +obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*) + $(phoenix_compile) + +obj/resource.o: $(ui)/resource.rc +# windres --target=pe-i386 $(ui)/resource.rc obj/resource.o + windres $(ui)/resource.rc obj/resource.o + +# targets +build: $(objects) +ifeq ($(platform),osx) + test -d ../$(name).app || mkdir -p ../$(name).app/Contents/MacOS + $(strip $(cpp) -o ../$(name).app/Contents/MacOS/$(name) $(objects) $(link)) +else + $(strip $(cpp) -o out/$(name) $(objects) $(link)) +endif + +install: +ifeq ($(platform),x) + install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name) + mkdir -p ~/.config/$(name) + install -D -m 644 data/$(name).png $(DESTDIR)$(prefix)/share/pixmaps/$(name).png + install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop + cp data/cheats.bml ~/.config/$(name)/cheats.bml + chmod 777 ~/.config/$(name) ~/.config/$(name)/cheats.bml +endif + +uninstall: +ifeq ($(platform),x) + rm $(DESTDIR)$(prefix)/bin/$(name) + rm $(DESTDIR)$(prefix)/share/pixmaps/$(name).png + rm $(DESTDIR)$(prefix)/share/applications/$(name).desktop +endif diff --git a/ui/base.hpp b/ui/base.hpp new file mode 100755 index 00000000..bc22c6c6 --- /dev/null +++ b/ui/base.hpp @@ -0,0 +1,53 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace nall; + +#include +using namespace phoenix; + +#include +using namespace ruby; + +#include "config/config.hpp" +#include "interface/interface.hpp" +#include "input/input.hpp" +#include "utility/utility.hpp" +#include "window/window.hpp" +#include "general/general.hpp" +#include "settings/settings.hpp" +#include "tools/tools.hpp" + +struct Application { + bool quit; + bool pause; + bool autopause; + bool compositionEnable; + + string basepath; + string userpath; + string path(const string &filename); + + string title; + string normalFont; + string boldFont; + string titleFont; + + void run(); + Application(int argc, char **argv); + ~Application(); +}; + +extern Application *application; +extern nall::DSP dspaudio; diff --git a/ui/config/config.cpp b/ui/config/config.cpp new file mode 100755 index 00000000..d8f46b62 --- /dev/null +++ b/ui/config/config.cpp @@ -0,0 +1,55 @@ +#include "../base.hpp" +Config *config = 0; + +Config::Config() { + attach(video.driver = "", "Video::Driver"); + attach(video.filter = "None", "Video::Filter"); + attach(video.shader = "Blur", "Video::Shader"); + attach(video.synchronize = true, "Video::Synchronize"); + attach(video.correctAspectRatio = true, "Video::CorrectAspectRatio"); + + attach(video.maskOverscan = false, "Video::MaskOverscan"); + attach(video.maskOverscanHorizontal = 8, "Video::MaskOverscanHorizontal"); + attach(video.maskOverscanVertical = 8, "Video::MaskOverscanVertical"); + + attach(video.brightness = 100, "Video::Brightness"); + attach(video.contrast = 100, "Video::Contrast"); + attach(video.gamma = 50, "Video::Gamma"); + + attach(video.fullScreenMode = 0, "Video::FullScreenMode"); + + attach(video.startFullScreen = false, "Video::StartFullScreen"); + attach(video.compositionMode = 0, "Video::CompositionMode"); + + attach(audio.driver = "", "Audio::Driver"); + attach(audio.synchronize = true, "Audio::Synchronize"); + attach(audio.mute = false, "Audio::Mute"); + attach(audio.volume = 100, "Audio::Volume"); + attach(audio.latency = 60, "Audio::Latency"); + attach(audio.resampler = "sinc", "Audio::Resampler"); + + attach(audio.frequency = 48000, "Audio::Frequency::Native"); + attach(audio.frequencyNES = 1789772, "Audio::Frequency::NES"); + attach(audio.frequencySNES = 32000, "Audio::Frequency::SNES"); + attach(audio.frequencyGameBoy = 4194304, "Audio::Frequency::GameBoy"); + + attach(input.driver = "", "Input::Driver"); + attach(input.focusPolicy = 1, "Input::FocusPolicy"); + + attach(path.bios.satellaview = "", "Path::BIOS::Satellaview"); + attach(path.bios.sufamiTurbo = "", "Path::BIOS::SufamiTurbo"); + attach(path.bios.superGameBoy = "", "Path::BIOS::SuperGameBoy"); + + attach(nes.controllerPort1Device = 1, "NES::Controller::Port1"); + attach(nes.controllerPort2Device = 0, "NES::Controller::Port2"); + + attach(snes.controllerPort1Device = 1, "SNES::Controller::Port1"); + attach(snes.controllerPort2Device = 0, "SNES::Controller::Port2"); + + load(application->path("settings.cfg")); + save(application->path("settings.cfg")); +} + +Config::~Config() { + save(application->path("settings.cfg")); +} diff --git a/ui/config/config.hpp b/ui/config/config.hpp new file mode 100755 index 00000000..a20041bd --- /dev/null +++ b/ui/config/config.hpp @@ -0,0 +1,64 @@ +struct Config : public configuration { + struct Video { + string driver; + string filter; + string shader; + bool synchronize; + bool correctAspectRatio; + + bool maskOverscan; + unsigned maskOverscanHorizontal; + unsigned maskOverscanVertical; + + unsigned brightness; + unsigned contrast; + unsigned gamma; + + unsigned fullScreenMode; + unsigned compositionMode; + + bool startFullScreen; + } video; + + struct Audio { + string driver; + bool synchronize; + bool mute; + unsigned volume; + unsigned latency; + string resampler; + + unsigned frequency; + unsigned frequencyNES; + unsigned frequencySNES; + unsigned frequencyGameBoy; + } audio; + + struct Input { + string driver; + unsigned focusPolicy; + } input; + + struct Path { + struct BIOS { + string satellaview; + string sufamiTurbo; + string superGameBoy; + } bios; + } path; + + struct NES { + unsigned controllerPort1Device; + unsigned controllerPort2Device; + } nes; + + struct SNES { + unsigned controllerPort1Device; + unsigned controllerPort2Device; + } snes; + + Config(); + ~Config(); +}; + +extern Config *config; diff --git a/ui/general/dip-switches.cpp b/ui/general/dip-switches.cpp new file mode 100755 index 00000000..311e50ca --- /dev/null +++ b/ui/general/dip-switches.cpp @@ -0,0 +1,69 @@ +DipSwitches *dipSwitches = 0; + +DipSwitch::DipSwitch() { + append(name, { ~0, 0 }, 5); + append(value, { ~0, 0 }, 0); +} + +DipSwitches::DipSwitches() { + setTitle("DIP Switches"); + + layout.setMargin(5); + acceptButton.setText("Accept"); + + append(layout); + for(unsigned n = 0; n < 8; n++) + layout.append(dip[n], { ~0, 0 }, 5); + layout.append(controlLayout, { ~0, 0 }, 5); + controlLayout.append(spacer, { ~0, 0 }, 0); + controlLayout.append(acceptButton, { 0, 0 }, 0); + + setGeometry({ 128, 128, 400, layout.minimumGeometry().height }); + windowManager->append(this, "DipSwitches"); + + acceptButton.onTick = { &DipSwitches::accept, this }; +} + +void DipSwitches::load() { + if(interface->mode() != Interface::Mode::SNES || SNES::cartridge.has_nss_dip() == false) return; + application->pause = true; + + auto info = SNES::cartridge.information.nss; + unsigned count = info.setting.size(); + + for(unsigned n = 0; n < min(8, count); n++) { + dip[n].setEnabled(true); + dip[n].name.setText(info.setting[n]); + dip[n].value.reset(); + for(unsigned z = 0; z < min(16, info.option[n].size()); z++) { + lstring part; + part.split<1>(":", info.option[n][z]); + values[n][z] = hex(part[0]); + dip[n].value.append(part[1]); + } + } + + for(unsigned n = count; n < 8; n++) { + dip[n].setEnabled(false); + dip[n].name.setText("(unused)"); + dip[n].value.reset(); + dip[n].value.append("(unused)"); + } + + acceptButton.setFocused(); + setVisible(); +} + +void DipSwitches::accept() { + auto info = SNES::cartridge.information.nss; + unsigned count = info.setting.size(); + + unsigned result = 0x0000; + for(unsigned n = 0; n < min(8, count); n++) { + result |= values[n][dip[n].value.selection()]; + } + + setVisible(false); + SNES::nss.set_dip(result); + application->pause = false; +} diff --git a/ui/general/dip-switches.hpp b/ui/general/dip-switches.hpp new file mode 100755 index 00000000..2b023738 --- /dev/null +++ b/ui/general/dip-switches.hpp @@ -0,0 +1,23 @@ +struct DipSwitch : HorizontalLayout { + Label name; + ComboBox value; + + DipSwitch(); +}; + +struct DipSwitches : Window { + VerticalLayout layout; + DipSwitch dip[8]; + HorizontalLayout controlLayout; + Widget spacer; + Button acceptButton; + + void load(); + void accept(); + DipSwitches(); + +private: + unsigned values[8][16]; +}; + +extern DipSwitches *dipSwitches; diff --git a/ui/general/file-browser.cpp b/ui/general/file-browser.cpp new file mode 100755 index 00000000..671fb3d6 --- /dev/null +++ b/ui/general/file-browser.cpp @@ -0,0 +1,153 @@ +FileBrowser *fileBrowser = 0; + +FileBrowser::FileBrowser() { + setGeometry({ 128, 128, 640, 400 }); + windowManager->append(this, "FileBrowser"); + + layout.setMargin(5); + pathBrowse.setText("Browse ..."); + pathUp.setText(".."); + openButton.setText("Open"); + + append(layout); + layout.append(pathLayout, { ~0, 0 }, 5); + pathLayout.append(pathEdit, { ~0, 0 }, 5); + pathLayout.append(pathBrowse, { 0, 0 }, 5); + pathLayout.append(pathUp, { 0, 0 }); + layout.append(fileList, { ~0, ~0 }, 5); + layout.append(controlLayout, { ~0, 0 }); + controlLayout.append(filterLabel, { ~0, 0 }, 5); + controlLayout.append(openButton, { 80, 0 }); + + pathEdit.onActivate = [&] { + string path = pathEdit.text(); + path.transform("\\", "/"); + if(path.endswith("/") == false) path.append("/"); + setPath(path); + }; + + pathBrowse.onTick = [&] { + string path = OS::folderSelect(*this, mode->path); + if(path != "") setPath(path); + }; + + pathUp.onTick = [&] { + if(mode->path == "/") return; + string path = mode->path; + path.rtrim<1>("/"); + path = dir(path); + setPath(path); + }; + + fileList.onChange = { &FileBrowser::synchronize, this }; + fileList.onActivate = openButton.onTick = { &FileBrowser::fileListActivate, this }; + + filterModes.append({ "Default", "", { "*" } }); + filterModes.append({ "NES", "", { "*.fc", "*.nes" } }); + filterModes.append({ "SNES", "", { "*.sfc" } }); + filterModes.append({ "GameBoy", "", { "*.gb", "*.gbc" } }); + filterModes.append({ "GameBoyColor", "", { "*.gbc" } }); + filterModes.append({ "Satellaview", "", { "*.bs" } }); + filterModes.append({ "SufamiTurbo", "", { "*.st" } }); + mode = &filterModes[Mode::Default]; + + for(auto &mode : filterModes) config.attach(mode.path, mode.name); + config.load(application->path("paths.cfg")); + config.save(application->path("paths.cfg")); + synchronize(); +} + +void FileBrowser::synchronize() { + openButton.setEnabled(fileList.selected()); +} + +FileBrowser::~FileBrowser() { + config.save(application->path("paths.cfg")); +} + +void FileBrowser::open(const string &title, unsigned requestedMode, function requestedCallback) { + callback = requestedCallback; + if(mode == &filterModes[requestedMode]) { + setVisible(); + fileList.setFocused(); + return; + } + mode = &filterModes[requestedMode]; + + setTitle(title); + setPath(mode->path); + + string filterText = "Files of type: "; + for(auto &filter : mode->filter) filterText.append(filter, ", "); + filterText.trim<1>(", "); + filterLabel.setText(filterText); + + setVisible(); + fileList.setFocused(); +} + +void FileBrowser::setPath(const string &path) { + mode->path = path; + if(mode->path == "") mode->path = application->basepath; + pathEdit.setText(mode->path); + + fileList.reset(); + fileNameList.reset(); + + lstring contentsList = directory::contents(path); + for(auto &fileName : contentsList) { + if(fileName.endswith("/")) { + fileNameList.append(fileName); + } else for(auto &filter : mode->filter) { + if(fileName.wildcard(filter)) { + fileNameList.append(fileName); + break; + } + } + } + + for(auto &fileName : fileNameList) fileList.append(fileName); + fileList.setSelection(0); + fileList.setFocused(); + synchronize(); +} + +void FileBrowser::fileListActivate() { + unsigned selection = fileList.selection(); + string fileName = fileNameList[selection]; + if(fileName.endswith("/")) { + if(loadFolder({ mode->path, fileName })) return; + return setPath({ mode->path, fileName }); + } + loadFile({ mode->path, fileName }); +} + +bool FileBrowser::loadFolder(const string &requestedPath) { + bool accept = false; + string path = requestedPath; + path.rtrim<1>("/"); + for(auto &filter : mode->filter) { + if(path.wildcard(filter)) accept = true; + } + if(accept == false) return false; + + lstring contentsList = directory::contents(requestedPath); + lstring fileNameList; + for(auto &fileName : contentsList) { + for(auto &filter : mode->filter) { + if(fileName.wildcard(filter)) { + fileNameList.append(fileName); + break; + } + } + } + + if(fileNameList.size() != 1) return false; + loadFile({ requestedPath, fileNameList[0] }); + return true; +} + +void FileBrowser::loadFile(const string &filename) { + if(callback) callback(filename); + setVisible(false); +} diff --git a/ui/general/file-browser.hpp b/ui/general/file-browser.hpp new file mode 100755 index 00000000..93ce2fef --- /dev/null +++ b/ui/general/file-browser.hpp @@ -0,0 +1,37 @@ +struct FileBrowser : Window { + VerticalLayout layout; + HorizontalLayout pathLayout; + LineEdit pathEdit; + Button pathBrowse; + Button pathUp; + ListView fileList; + HorizontalLayout controlLayout; + Label filterLabel; + Button openButton; + + struct Mode { enum : unsigned { Default, NES, SNES, GameBoy, GameBoyColor, Satellaview, SufamiTurbo }; }; + void open(const string &title, unsigned mode, function callback); + + FileBrowser(); + ~FileBrowser(); + +private: + configuration config; + struct FilterMode { + string name; + string path; + lstring filter; + } *mode; + vector filterModes; + + lstring fileNameList; + function callback; + + void synchronize(); + void setPath(const string &path); + void fileListActivate(); + bool loadFolder(const string &path); + void loadFile(const string &filename); +}; + +extern FileBrowser *fileBrowser; diff --git a/ui/general/general.cpp b/ui/general/general.cpp new file mode 100755 index 00000000..b8c55a30 --- /dev/null +++ b/ui/general/general.cpp @@ -0,0 +1,5 @@ +#include "../base.hpp" +#include "main-window.cpp" +#include "file-browser.cpp" +#include "slot-loader.cpp" +#include "dip-switches.cpp" diff --git a/ui/general/general.hpp b/ui/general/general.hpp new file mode 100755 index 00000000..ab6a06af --- /dev/null +++ b/ui/general/general.hpp @@ -0,0 +1,4 @@ +#include "main-window.hpp" +#include "file-browser.hpp" +#include "slot-loader.hpp" +#include "dip-switches.hpp" diff --git a/ui/general/main-window.cpp b/ui/general/main-window.cpp new file mode 100755 index 00000000..9f6f749d --- /dev/null +++ b/ui/general/main-window.cpp @@ -0,0 +1,396 @@ +MainWindow *mainWindow = 0; + +MainWindow::MainWindow() { + setTitle(application->title); + setGeometry({ 256, 256, 626, 480 }); + setBackgroundColor({ 0, 0, 0 }); + windowManager->append(this, "MainWindow"); + + cartridgeMenu.setText("Cartridge"); + cartridgeLoadSNES.setText("Load SNES Cartridge ..."); + cartridgeLoadNES.setText("Load NES Cartridge ..."); + cartridgeLoadGameBoy.setText("Load Game Boy Cartridge ..."); + cartridgeLoadGameBoyColor.setText("Load Game Boy Color Cartridge ..."); + cartridgeLoadSatellaviewSlotted.setText("Load Satellaview-Slotted Cartridge ..."); + cartridgeLoadSatellaview.setText("Load Satellaview Cartridge ..."); + cartridgeLoadSufamiTurbo.setText("Load Sufami Turbo Cartridge ..."); + cartridgeLoadSuperGameBoy.setText("Load Super Game Boy Cartridge ..."); + + nesMenu.setText("NES"); + nesPower.setText("Power Cycle"); + nesReset.setText("Reset"); + nesPort1.setText("Controller Port 1"); + nesPort1Device[0].setText("None"); + nesPort1Device[1].setText("Gamepad"); + RadioItem::group(nesPort1Device[0], nesPort1Device[1]); + nesPort1Device[config->nes.controllerPort1Device].setChecked(); + nesPort2.setText("Controller Port 2"); + nesPort2Device[0].setText("None"); + nesPort2Device[1].setText("Gamepad"); + RadioItem::group(nesPort2Device[0], nesPort2Device[1]); + nesPort2Device[config->nes.controllerPort2Device].setChecked(); + nesCartridgeUnload.setText("Unload Cartridge"); + + snesMenu.setText("SNES"); + snesPower.setText("Power Cycle"); + snesReset.setText("Reset"); + snesPort1.setText("Controller Port 1"); + snesPort1Device[0].setText("None"); + snesPort1Device[1].setText("Gamepad"); + snesPort1Device[2].setText("Multitap"); + snesPort1Device[3].setText("Mouse"); + RadioItem::group(snesPort1Device[0], snesPort1Device[1], snesPort1Device[2], snesPort1Device[3]); + snesPort1Device[config->snes.controllerPort1Device].setChecked(); + snesPort2.setText("Controller Port 2"); + snesPort2Device[0].setText("None"); + snesPort2Device[1].setText("Gamepad"); + snesPort2Device[2].setText("Multitap"); + snesPort2Device[3].setText("Mouse"); + snesPort2Device[4].setText("Super Scope"); + snesPort2Device[5].setText("Justifier"); + snesPort2Device[6].setText("Dual Justifiers"); + snesPort2Device[7].setText("Serial Cable"); + RadioItem::group(snesPort2Device[0], snesPort2Device[1], snesPort2Device[2], snesPort2Device[3], + snesPort2Device[4], snesPort2Device[5], snesPort2Device[6], snesPort2Device[7]); + snesPort2Device[config->snes.controllerPort2Device].setChecked(); + snesCartridgeUnload.setText("Unload Cartridge"); + + gameBoyMenu.setText("Game Boy"); + gameBoyPower.setText("Power Cycle"); + gameBoyCartridgeUnload.setText("Unload Cartridge"); + + settingsMenu.setText("Settings"); + settingsVideoFilter.setText("Video Filter"); + settingsVideoFilterNone.setText("None"); + setupVideoFilters(); + settingsVideoShader.setText("Video Shader"); + settingsVideoShaderNone.setText("None"); + settingsVideoShaderBlur.setText("Blur"); + setupVideoShaders(); + settingsSynchronizeVideo.setText("Synchronize Video"); + settingsSynchronizeVideo.setChecked(config->video.synchronize); + settingsSynchronizeAudio.setText("Synchronize Audio"); + settingsSynchronizeAudio.setChecked(config->audio.synchronize); + settingsCorrectAspectRatio.setText("Correct Aspect Ratio"); + settingsCorrectAspectRatio.setChecked(config->video.correctAspectRatio); + settingsMaskOverscan.setText("Mask Overscan"); + settingsMaskOverscan.setChecked(config->video.maskOverscan); + settingsMuteAudio.setText("Mute Audio"); + settingsMuteAudio.setChecked(config->audio.mute); + settingsConfiguration.setText("Configuration ..."); + + toolsMenu.setText("Tools"); + toolsStateSave.setText("Save State"); + toolsStateSave1.setText("Slot 1"); + toolsStateSave2.setText("Slot 2"); + toolsStateSave3.setText("Slot 3"); + toolsStateSave4.setText("Slot 4"); + toolsStateSave5.setText("Slot 5"); + toolsStateLoad.setText("Load State"); + toolsStateLoad1.setText("Slot 1"); + toolsStateLoad2.setText("Slot 2"); + toolsStateLoad3.setText("Slot 3"); + toolsStateLoad4.setText("Slot 4"); + toolsStateLoad5.setText("Slot 5"); + toolsShrinkWindow.setText("Shrink Window"); + toolsCheatEditor.setText("Cheat Editor ..."); + toolsStateManager.setText("State Manager ..."); + + append(cartridgeMenu); + cartridgeMenu.append(cartridgeLoadNES); + cartridgeMenu.append(cartridgeLoadSNES); + cartridgeMenu.append(cartridgeLoadGameBoy); + cartridgeMenu.append(cartridgeLoadGameBoyColor); + cartridgeMenu.append(cartridgeSeparator); + cartridgeMenu.append(cartridgeLoadSatellaviewSlotted); + cartridgeMenu.append(cartridgeLoadSatellaview); + cartridgeMenu.append(cartridgeLoadSufamiTurbo); + cartridgeMenu.append(cartridgeLoadSuperGameBoy); + + append(nesMenu); + nesMenu.append(nesPower); + nesMenu.append(nesReset); + nesMenu.append(nesSeparator1); + nesMenu.append(nesPort1); + nesPort1.append(nesPort1Device[0]); + nesPort1.append(nesPort1Device[1]); + nesMenu.append(nesPort2); + nesPort2.append(nesPort2Device[0]); + nesPort2.append(nesPort2Device[1]); + nesMenu.append(nesSeparator2); + nesMenu.append(nesCartridgeUnload); + + append(snesMenu); + snesMenu.append(snesPower); + snesMenu.append(snesReset); + snesMenu.append(snesSeparator1); + snesMenu.append(snesPort1); + snesPort1.append(snesPort1Device[0]); + snesPort1.append(snesPort1Device[1]); + snesPort1.append(snesPort1Device[2]); + snesPort1.append(snesPort1Device[3]); + snesMenu.append(snesPort2); + snesPort2.append(snesPort2Device[0]); + snesPort2.append(snesPort2Device[1]); + snesPort2.append(snesPort2Device[2]); + snesPort2.append(snesPort2Device[3]); + snesPort2.append(snesPort2Device[4]); + snesPort2.append(snesPort2Device[5]); + snesPort2.append(snesPort2Device[6]); + snesPort2.append(snesPort2Device[7]); + snesMenu.append(snesSeparator2); + snesMenu.append(snesCartridgeUnload); + + append(gameBoyMenu); + gameBoyMenu.append(gameBoyPower); + gameBoyMenu.append(gameBoySeparator); + gameBoyMenu.append(gameBoyCartridgeUnload); + + append(settingsMenu); + settingsMenu.append(settingsVideoFilter); + settingsVideoFilter.append(settingsVideoFilterNone); + if(videoFilterName.size()) + settingsVideoFilter.append(settingsVideoFilterSeparator); + for(unsigned n = 0; n < videoFilterName.size(); n++) + settingsVideoFilter.append(settingsVideoFilterList[n]); + settingsMenu.append(settingsVideoShader); + settingsVideoShader.append(settingsVideoShaderNone); + settingsVideoShader.append(settingsVideoShaderBlur); + if(videoShaderName.size()) + settingsVideoShader.append(settingsVideoShaderSeparator); + for(unsigned n = 0; n < videoShaderName.size(); n++) + settingsVideoShader.append(settingsVideoShaderList[n]); + settingsMenu.append(settingsSeparator1); + settingsMenu.append(settingsSynchronizeVideo); + settingsMenu.append(settingsSynchronizeAudio); + settingsMenu.append(settingsSeparator2); + settingsMenu.append(settingsCorrectAspectRatio); + settingsMenu.append(settingsMaskOverscan); + settingsMenu.append(settingsMuteAudio); + settingsMenu.append(settingsSeparator3); + settingsMenu.append(settingsConfiguration); + + append(toolsMenu); + toolsMenu.append(toolsStateSave); + toolsStateSave.append(toolsStateSave1); + toolsStateSave.append(toolsStateSave2); + toolsStateSave.append(toolsStateSave3); + toolsStateSave.append(toolsStateSave4); + toolsStateSave.append(toolsStateSave5); + toolsMenu.append(toolsStateLoad); + toolsStateLoad.append(toolsStateLoad1); + toolsStateLoad.append(toolsStateLoad2); + toolsStateLoad.append(toolsStateLoad3); + toolsStateLoad.append(toolsStateLoad4); + toolsStateLoad.append(toolsStateLoad5); + toolsMenu.append(toolsSeparator); + toolsMenu.append(toolsShrinkWindow); + toolsMenu.append(toolsCheatEditor); + toolsMenu.append(toolsStateManager); + + setMenuVisible(); + + setStatusText("No cartridge loaded"); + setStatusVisible(); + + layout.append(viewport, { 0, 0, 512, 480 }); + append(layout); + + onClose = [&] { application->quit = true; }; + onSize = [&] { utility->resizeMainWindow(); }; + + cartridgeLoadNES.onTick = [&] { + fileBrowser->open("Load Cartridge - NES", FileBrowser::Mode::NES, [](string filename) { + interface->nes.loadCartridge(filename); + }); + }; + + cartridgeLoadSNES.onTick = [&] { + fileBrowser->open("Load Cartridge - SNES", FileBrowser::Mode::SNES, [](string filename) { + interface->snes.loadCartridge(filename); + }); + }; + + cartridgeLoadGameBoy.onTick = [&] { + fileBrowser->open("Load Cartridge - Game Boy", FileBrowser::Mode::GameBoy, [](string filename) { + interface->gameBoy.loadCartridge(GameBoy::System::Revision::GameBoy, filename); + }); + }; + + cartridgeLoadGameBoyColor.onTick = [&] { + fileBrowser->open("Load Cartridge - Game Boy Color", FileBrowser::Mode::GameBoyColor, [](string filename) { + interface->gameBoy.loadCartridge(GameBoy::System::Revision::GameBoyColor, filename); + }); + }; + + cartridgeLoadSatellaviewSlotted.onTick = [&] { slotLoader->loadSatellaviewSlotted(); }; + cartridgeLoadSatellaview.onTick = [&] { slotLoader->loadSatellaview(); }; + cartridgeLoadSufamiTurbo.onTick = [&] { slotLoader->loadSufamiTurbo(); }; + cartridgeLoadSuperGameBoy.onTick = [&] { slotLoader->loadSuperGameBoy(); }; + + nesPower.onTick = { &Interface::power, interface }; + nesReset.onTick = { &Interface::reset, interface }; + + nesPort1Device[0].onTick = [&] { interface->setController(0, 0); }; + nesPort1Device[1].onTick = [&] { interface->setController(0, 1); }; + + nesPort2Device[0].onTick = [&] { interface->setController(1, 0); }; + nesPort2Device[1].onTick = [&] { interface->setController(1, 1); }; + + nesCartridgeUnload.onTick = { &Interface::unloadCartridge, interface }; + + snesPower.onTick = { &Interface::power, interface }; + snesReset.onTick = { &Interface::reset, interface }; + + snesPort1Device[0].onTick = [&] { interface->setController(0, 0); }; + snesPort1Device[1].onTick = [&] { interface->setController(0, 1); }; + snesPort1Device[2].onTick = [&] { interface->setController(0, 2); }; + snesPort1Device[3].onTick = [&] { interface->setController(0, 3); }; + + snesPort2Device[0].onTick = [&] { interface->setController(1, 0); }; + snesPort2Device[1].onTick = [&] { interface->setController(1, 1); }; + snesPort2Device[2].onTick = [&] { interface->setController(1, 2); }; + snesPort2Device[3].onTick = [&] { interface->setController(1, 3); }; + snesPort2Device[4].onTick = [&] { interface->setController(1, 4); }; + snesPort2Device[5].onTick = [&] { interface->setController(1, 5); }; + snesPort2Device[6].onTick = [&] { interface->setController(1, 6); }; + snesPort2Device[7].onTick = [&] { interface->setController(1, 7); }; + + snesCartridgeUnload.onTick = { &Interface::unloadCartridge, interface }; + + gameBoyPower.onTick = { &Interface::power, interface }; + gameBoyCartridgeUnload.onTick = { &Interface::unloadCartridge, interface }; + + settingsVideoFilterNone.onTick = [&] { + config->video.filter = "None"; + utility->bindVideoFilter(); + }; + + settingsVideoShaderNone.onTick = [&] { + config->video.shader = "None"; + utility->bindVideoShader(); + }; + + settingsVideoShaderBlur.onTick = [&] { + config->video.shader = "Blur"; + utility->bindVideoShader(); + }; + + settingsSynchronizeVideo.onTick = [&] { + config->video.synchronize = settingsSynchronizeVideo.checked(); + video.set(Video::Synchronize, config->video.synchronize); + }; + + settingsSynchronizeAudio.onTick = [&] { + config->audio.synchronize = settingsSynchronizeAudio.checked(); + audio.set(Audio::Synchronize, config->audio.synchronize); + }; + + settingsCorrectAspectRatio.onTick = [&] { + config->video.correctAspectRatio = settingsCorrectAspectRatio.checked(); + utility->resizeMainWindow(); + }; + + settingsMaskOverscan.onTick = [&] { + config->video.maskOverscan = settingsMaskOverscan.checked(); + }; + + settingsMuteAudio.onTick = [&] { + config->audio.mute = settingsMuteAudio.checked(); + dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0); + }; + + settingsConfiguration.onTick = [&] { settingsWindow->setVisible(); }; + + toolsStateSave1.onTick = [&] { interface->saveState(1); }; + toolsStateSave2.onTick = [&] { interface->saveState(2); }; + toolsStateSave3.onTick = [&] { interface->saveState(3); }; + toolsStateSave4.onTick = [&] { interface->saveState(4); }; + toolsStateSave5.onTick = [&] { interface->saveState(5); }; + + toolsStateLoad1.onTick = [&] { interface->loadState(1); }; + toolsStateLoad2.onTick = [&] { interface->loadState(2); }; + toolsStateLoad3.onTick = [&] { interface->loadState(3); }; + toolsStateLoad4.onTick = [&] { interface->loadState(4); }; + toolsStateLoad5.onTick = [&] { interface->loadState(5); }; + + toolsShrinkWindow.onTick = [&] { utility->resizeMainWindow(true); }; + toolsCheatEditor.onTick = [&] { cheatEditor->setVisible(); }; + toolsStateManager.onTick = [&] { stateManager->setVisible(); }; + + synchronize(); +} + +void MainWindow::synchronize() { + if(interface->cartridgeLoaded()) { + toolsStateSave.setEnabled(true); + toolsStateLoad.setEnabled(true); + } else { + toolsStateSave.setEnabled(false); + toolsStateLoad.setEnabled(false); + } +} + +void MainWindow::setupVideoFilters() { + string path = { application->basepath, "filters/" }; + lstring files = directory::files(path, "*.filter"); + if(files.size() == 0) { + path = { application->userpath, "filters/" }; + files = directory::files(path, "*.filter"); + } + reference_array group; + + settingsVideoFilterList = new RadioItem[files.size()]; + for(unsigned n = 0; n < files.size(); n++) { + string name = files[n]; + videoFilterName.append({ path, name }); + if(auto position = name.position(".filter")) name[position()] = 0; + + settingsVideoFilterList[n].setText(name); + settingsVideoFilterList[n].onTick = [&, n] { + config->video.filter = videoFilterName[n]; + utility->bindVideoFilter(); + }; + } + + group.append(settingsVideoFilterNone); + for(unsigned n = 0; n < files.size(); n++) group.append(settingsVideoFilterList[n]); + RadioItem::group(group); + + if(config->video.filter == "None") settingsVideoFilterNone.setChecked(); + for(unsigned n = 0; n < files.size(); n++) + if(config->video.filter == videoFilterName[n]) settingsVideoFilterList[n].setChecked(); +} + +void MainWindow::setupVideoShaders() { + string path = { application->basepath, "shaders/" }; + lstring files = directory::files(path, { "*.", config->video.driver, ".shader" }); + if(files.size() == 0) { + path = { application->userpath, "shaders/" }; + files = directory::files(path, { "*.", config->video.driver, ".shader" }); + } + reference_array group; + + settingsVideoShaderList = new RadioItem[files.size()]; + for(unsigned n = 0; n < files.size(); n++) { + string name = files[n]; + videoShaderName.append({ path, name }); + if(auto position = name.position(string{ ".", config->video.driver, ".shader" })) name[position()] = 0; + + settingsVideoShaderList[n].setText(name); + settingsVideoShaderList[n].onTick = [&, n] { + config->video.shader = videoShaderName[n]; + utility->bindVideoShader(); + }; + } + + group.append(settingsVideoShaderNone); + group.append(settingsVideoShaderBlur); + for(unsigned n = 0; n < files.size(); n++) group.append(settingsVideoShaderList[n]); + RadioItem::group(group); + + if(config->video.shader == "None") settingsVideoShaderNone.setChecked(); + if(config->video.shader == "Blur") settingsVideoShaderBlur.setChecked(); + for(unsigned n = 0; n < files.size(); n++) + if(config->video.shader == videoShaderName[n]) settingsVideoShaderList[n].setChecked(); +} diff --git a/ui/general/main-window.hpp b/ui/general/main-window.hpp new file mode 100755 index 00000000..b595755a --- /dev/null +++ b/ui/general/main-window.hpp @@ -0,0 +1,92 @@ +struct MainWindow : Window { + FixedLayout layout; + Viewport viewport; + + Menu cartridgeMenu; + Item cartridgeLoadSNES; + Item cartridgeLoadNES; + Item cartridgeLoadGameBoy; + Item cartridgeLoadGameBoyColor; + Separator cartridgeSeparator; + Item cartridgeLoadSatellaviewSlotted; + Item cartridgeLoadSatellaview; + Item cartridgeLoadSufamiTurbo; + Item cartridgeLoadSuperGameBoy; + + Menu nesMenu; + Item nesPower; + Item nesReset; + Separator nesSeparator1; + Menu nesPort1; + RadioItem nesPort1Device[2]; + Menu nesPort2; + RadioItem nesPort2Device[2]; + Separator nesSeparator2; + Item nesCartridgeUnload; + + Menu snesMenu; + Item snesPower; + Item snesReset; + Separator snesSeparator1; + Menu snesPort1; + RadioItem snesPort1Device[4]; + Menu snesPort2; + RadioItem snesPort2Device[8]; + Separator snesSeparator2; + Item snesCartridgeUnload; + + Menu gameBoyMenu; + Item gameBoyPower; + Separator gameBoySeparator; + Item gameBoyCartridgeUnload; + + Menu settingsMenu; + Menu settingsVideoFilter; + RadioItem settingsVideoFilterNone; + Separator settingsVideoFilterSeparator; + RadioItem *settingsVideoFilterList; + Menu settingsVideoShader; + RadioItem settingsVideoShaderNone; + RadioItem settingsVideoShaderBlur; + Separator settingsVideoShaderSeparator; + RadioItem *settingsVideoShaderList; + Separator settingsSeparator1; + CheckItem settingsSynchronizeVideo; + CheckItem settingsSynchronizeAudio; + Separator settingsSeparator2; + CheckItem settingsCorrectAspectRatio; + CheckItem settingsMaskOverscan; + CheckItem settingsMuteAudio; + Separator settingsSeparator3; + Item settingsConfiguration; + + Menu toolsMenu; + Menu toolsStateSave; + Item toolsStateSave1; + Item toolsStateSave2; + Item toolsStateSave3; + Item toolsStateSave4; + Item toolsStateSave5; + Menu toolsStateLoad; + Item toolsStateLoad1; + Item toolsStateLoad2; + Item toolsStateLoad3; + Item toolsStateLoad4; + Item toolsStateLoad5; + Separator toolsSeparator; + Item toolsShrinkWindow; + Item toolsCheatEditor; + Item toolsStateManager; + + void synchronize(); + MainWindow(); + +private: + lstring videoFilterName; + lstring videoShaderName; + + void setupVideoFilters(); + void setupVideoShaders(); +}; + +extern MainWindow *mainWindow; diff --git a/ui/general/slot-loader.cpp b/ui/general/slot-loader.cpp new file mode 100755 index 00000000..dcf1bc16 --- /dev/null +++ b/ui/general/slot-loader.cpp @@ -0,0 +1,185 @@ +SlotLoader *slotLoader = 0; + +SlotLoaderPath::SlotLoaderPath() { + browse.setText("Browse ..."); + append(label, { 40, 0 }, 5); + append(path, { ~0, 0 }, 5); + append(browse, { 80, 0 }, 0); +} + +SlotLoader::SlotLoader() { + layout.setMargin(5); + base.label.setText("Base:"); + slot[0].label.setText("Slot:"); + slot[1].label.setText("Slot:"); + loadButton.setText("Load"); + + append(layout); + layout.append(base, { ~0, 0 }, 5); + layout.append(slot[0], { ~0, 0 }, 5); + layout.append(slot[1], { ~0, 0 }, 5); + layout.append(controlLayout, { ~0, 0 }, 0); + controlLayout.append(spacer, { ~0, 0 }, 0); + controlLayout.append(loadButton, { 80, 0 }, 0); + + setGeometry({ 128, 128, 500, layout.minimumGeometry().height }); + windowManager->append(this, "SlotLoader"); +} + +void SlotLoader::synchronize() { + loadButton.setEnabled(base.path.text() != ""); +} + +void SlotLoader::loadSatellaviewSlotted() { + setTitle("Load Cartridge - Satellaview-Slotted"); + + base.path.setText(""); + + slot[0].path.setText(""); + slot[0].path.setEnabled(true); + slot[0].browse.setEnabled(true); + + slot[1].path.setText(""); + slot[1].path.setEnabled(false); + slot[1].browse.setEnabled(false); + + base.browse.onTick = [&] { + fileBrowser->open("Load Cartridge - SNES", FileBrowser::Mode::SNES, [&](const string &filename) { + base.path.setText(filename); + synchronize(); + }); + }; + + slot[0].browse.onTick = [&] { + fileBrowser->open("Load Cartridge - Satellaview", FileBrowser::Mode::Satellaview, [&](const string &filename) { + slot[0].path.setText(filename); + synchronize(); + }); + }; + + loadButton.onTick = [&] { + this->setVisible(false); + interface->snes.loadSatellaviewSlottedCartridge(base.path.text(), slot[0].path.text()); + }; + + synchronize(); + setVisible(); +} + +void SlotLoader::loadSatellaview() { + setTitle("Load Cartridge - Satellaview"); + + base.path.setText(config->path.bios.satellaview); + + slot[0].path.setText(""); + slot[0].path.setEnabled(true); + slot[0].browse.setEnabled(true); + + slot[1].path.setText(""); + slot[1].path.setEnabled(false); + slot[1].browse.setEnabled(false); + + base.browse.onTick = [&] { + fileBrowser->open("Load BIOS - Satellaview", FileBrowser::Mode::SNES, [&](const string &filename) { + config->path.bios.satellaview = filename; + base.path.setText(filename); + synchronize(); + }); + }; + + slot[0].browse.onTick = [&] { + fileBrowser->open("Load Cartridge - Satellaview", FileBrowser::Mode::Satellaview, [&](const string &filename) { + slot[0].path.setText(filename); + synchronize(); + }); + }; + + loadButton.onTick = [&] { + this->setVisible(false); + interface->snes.loadSatellaviewCartridge(base.path.text(), slot[0].path.text()); + }; + + synchronize(); + setVisible(); +} + +void SlotLoader::loadSufamiTurbo() { + setTitle("Load Cartridge - Sufami Turbo"); + + base.path.setText(config->path.bios.sufamiTurbo); + + slot[0].path.setText(""); + slot[0].path.setEnabled(true); + slot[0].browse.setEnabled(true); + + slot[1].path.setText(""); + slot[1].path.setEnabled(true); + slot[1].browse.setEnabled(true); + + base.browse.onTick = [&] { + fileBrowser->open("Load BIOS - Sufami Turbo", FileBrowser::Mode::SNES, [&](const string &filename) { + config->path.bios.sufamiTurbo = filename; + base.path.setText(filename); + synchronize(); + }); + }; + + slot[0].browse.onTick = [&] { + fileBrowser->open("Load Cartridge - Sufami Turbo", FileBrowser::Mode::SufamiTurbo, [&](const string &filename) { + slot[0].path.setText(filename); + synchronize(); + }); + }; + + slot[1].browse.onTick = [&] { + fileBrowser->open("Load Cartridge - Sufami Turbo", FileBrowser::Mode::SufamiTurbo, [&](const string &filename) { + slot[1].path.setText(filename); + synchronize(); + }); + }; + + loadButton.onTick = [&] { + this->setVisible(false); + interface->snes.loadSufamiTurboCartridge(base.path.text(), slot[0].path.text(), slot[1].path.text()); + }; + + synchronize(); + setVisible(); +} + +void SlotLoader::loadSuperGameBoy() { + setTitle("Load Cartridge - Super Game Boy"); + + base.path.setText(config->path.bios.superGameBoy); + + slot[0].path.setText(""); + slot[0].path.setEnabled(true); + slot[0].browse.setEnabled(true); + + slot[1].path.setText(""); + slot[1].path.setEnabled(false); + slot[1].browse.setEnabled(false); + + base.browse.onTick = [&] { + fileBrowser->open("Load BIOS - Super Game Boy", FileBrowser::Mode::SNES, [&](const string &filename) { + config->path.bios.superGameBoy = filename; + base.path.setText(filename); + synchronize(); + }); + }; + + slot[0].browse.onTick = [&] { + fileBrowser->open("Load Cartridge - Game Boy", FileBrowser::Mode::GameBoy, [&](const string &filename) { + slot[0].path.setText(filename); + synchronize(); + }); + }; + + loadButton.onTick = [&] { + this->setVisible(false); + interface->snes.loadSuperGameBoyCartridge(base.path.text(), slot[0].path.text()); + }; + + synchronize(); + setVisible(); +} diff --git a/ui/general/slot-loader.hpp b/ui/general/slot-loader.hpp new file mode 100755 index 00000000..d86cb0e5 --- /dev/null +++ b/ui/general/slot-loader.hpp @@ -0,0 +1,29 @@ +struct SlotLoaderPath : HorizontalLayout { + Label label; + LineEdit path; + Button browse; + + string name; + lstring filter; + + SlotLoaderPath(); +}; + +struct SlotLoader : Window { + VerticalLayout layout; + SlotLoaderPath base; + SlotLoaderPath slot[2]; + HorizontalLayout controlLayout; + Widget spacer; + Button loadButton; + + void synchronize(); + void loadSatellaviewSlotted(); + void loadSatellaview(); + void loadSufamiTurbo(); + void loadSuperGameBoy(); + + SlotLoader(); +}; + +extern SlotLoader *slotLoader; diff --git a/ui/input/gameboy.cpp b/ui/input/gameboy.cpp new file mode 100755 index 00000000..c8b9bbe2 --- /dev/null +++ b/ui/input/gameboy.cpp @@ -0,0 +1,53 @@ +int16_t GameBoyController::poll(unsigned n) { + switch(n) { + case 0: return up.poll() & !down.poll(); + case 1: return down.poll() & !up.poll(); + case 2: return left.poll() & !right.poll(); + case 3: return right.poll() & !left.poll(); + case 4: return b.poll() | bTurbo.poll(); + case 5: return a.poll() | aTurbo.poll(); + case 6: return select.poll(); + case 7: return start.poll(); + } + return 0; +} + +GameBoyController::GameBoyController() { + name = "Controller"; + + up.name = "Up"; + down.name = "Down"; + left.name = "Left"; + right.name = "Right"; + b.name = "B"; + a.name = "A"; + select.name = "Select"; + start.name = "Start"; + bTurbo.name = "Turbo B"; + aTurbo.name = "Turbo A"; + + up.mapping = "KB0::Up"; + down.mapping = "KB0::Down"; + left.mapping = "KB0::Left"; + right.mapping = "KB0::Right"; + b.mapping = "KB0::Z"; + a.mapping = "KB0::X"; + select.mapping = "KB0::Apostrophe"; + start.mapping = "KB0::Return"; + + append(up, down, left, right, b, a, select, start, bTurbo, aTurbo); +} + +// + +GameBoyDevice::GameBoyDevice() { + name = "Device"; + append(controller); +} + +// + +GameBoyInput::GameBoyInput() { + name = "Game Boy"; + append(device); +} diff --git a/ui/input/gameboy.hpp b/ui/input/gameboy.hpp new file mode 100755 index 00000000..41159fff --- /dev/null +++ b/ui/input/gameboy.hpp @@ -0,0 +1,20 @@ +struct GameBoyController : TertiaryInput { + DigitalInput up, down, left, right; + DigitalInput b, a, select, start; + TurboInput bTurbo, aTurbo; + + int16_t poll(unsigned n); + GameBoyController(); +}; + +struct GameBoyDevice : SecondaryInput { + GameBoyController controller; + + GameBoyDevice(); +}; + +struct GameBoyInput : PrimaryInput { + GameBoyDevice device; + + GameBoyInput(); +}; diff --git a/ui/input/input.cpp b/ui/input/input.cpp new file mode 100755 index 00000000..b64bddba --- /dev/null +++ b/ui/input/input.cpp @@ -0,0 +1,212 @@ +#include "../base.hpp" +#include "nes.cpp" +#include "snes.cpp" +#include "gameboy.cpp" +#include "user-interface.cpp" +InputManager *inputManager = 0; + +void AbstractInput::attach(const string &primaryName, const string &secondaryName, const string &tertiaryName) { + string name = { primaryName, "::", secondaryName, "::", tertiaryName, "::", this->name }; + name.replace(" ", ""); + inputManager->config.attach(mapping, name); +} + +void AbstractInput::bind() { + if(mapping == "") type = Type::Button, mapping = "None"; + + if(mapping.endswith(".Up")) type = Type::HatUp; + else if(mapping.endswith(".Down")) type = Type::HatDown; + else if(mapping.endswith(".Left")) type = Type::HatLeft; + else if(mapping.endswith(".Right")) type = Type::HatRight; + else if(mapping.endswith(".Lo")) type = Type::AxisLo; + else if(mapping.endswith(".Hi")) type = Type::AxisHi; + else if(mapping.beginswith("JP") && mapping.position("Axis")) type = Type::Axis; + else if(mapping.beginswith("MS") && mapping.endswith("axis")) type = Type::MouseAxis; + else if(mapping.beginswith("MS")) type = Type::MouseButton; + else type = Type::Button; + + string decode = mapping; + if(auto position = decode.position(".")) decode[position()] = 0; + scancode = Scancode::decode(decode); +} + +int16_t AbstractInput::poll() { + if(config->input.focusPolicy == 1 && mainWindow->focused() == false) return 0; + return inputManager->scancode[inputManager->activeScancode][scancode]; +} + +// + +bool AnalogInput::bind(int16_t scancode, int16_t value) { + string encode = Scancode::encode(scancode); + Type type = Type::Button; + + if(scancode == Scancode::None) goto bind; + if(Mouse::isAnyAxis(scancode)) { type = Type::MouseAxis; goto bind; } + if(Joypad::isAnyAxis(scancode)) { type = Type::Axis; goto bind; } + + return false; + +bind: + mapping = encode; + this->scancode = scancode; + this->type = Type::Axis; + return true; +} + +int16_t AnalogInput::poll() { + int16_t value = AbstractInput::poll(); + switch(type) { + case Type::MouseAxis: return input.acquired() ? value : 0; + case Type::Axis: return value; + } + return 0; +} + +// + +bool DigitalInput::bind(int16_t scancode, int16_t value) { + string encode = Scancode::encode(scancode); + Type type = Type::Button; + + if(scancode == Scancode::None) goto bind; + + if(Keyboard::isAnyKey(scancode) || Keyboard::isAnyModifier(scancode) || Joypad::isAnyButton(scancode)) { + if(value == 0) return false; + type = Type::Button; + goto bind; + } + + if(Mouse::isAnyButton(scancode)) { + if(value == 0) return false; + type = Type::MouseButton; + goto bind; + } + + if(Joypad::isAnyHat(scancode)) { + if(value & Joypad::HatUp ) { type = Type::HatUp; encode.append(".Up" ); goto bind; } + if(value & Joypad::HatDown ) { type = Type::HatDown; encode.append(".Down" ); goto bind; } + if(value & Joypad::HatLeft ) { type = Type::HatLeft; encode.append(".Left" ); goto bind; } + if(value & Joypad::HatRight) { type = Type::HatRight; encode.append(".Right"); goto bind; } + } + + if(Joypad::isAnyAxis(scancode)) { + if(value < -12288) { type = Type::AxisLo; encode.append(".Lo"); goto bind; } + if(value > +24576) { type = Type::AxisHi; encode.append(".Hi"); goto bind; } + } + + return false; + +bind: + mapping = encode; + this->scancode = scancode; + this->type = type; + return true; +} + +int16_t DigitalInput::poll() { + int16_t value = AbstractInput::poll(); + switch(type) { + case Type::Button: return (bool)(value); + case Type::MouseButton: return (bool)(value & input.acquired()); + case Type::HatUp: return (bool)(value & Joypad::HatUp); + case Type::HatDown: return (bool)(value & Joypad::HatDown); + case Type::HatLeft: return (bool)(value & Joypad::HatLeft); + case Type::HatRight: return (bool)(value & Joypad::HatRight); + case Type::AxisLo: return (bool)(value < -16384); + case Type::AxisHi: return (bool)(value > +16384); + } + return 0; +} + +// + +int16_t TurboInput::poll() { + int16_t result = DigitalInput::poll(); + if(phase < 3) result = 0; + if(++phase >= 6) phase = 0; + return result; +} + +TurboInput::TurboInput() : phase(0) { +} + +// + +void TertiaryInput::attach(const string &primaryName, const string &secondaryName) { + for(unsigned n = 0; n < size(); n++) { + operator[](n).attach(primaryName, secondaryName, name); + } +} + +void TertiaryInput::bind() { + for(unsigned n = 0; n < size(); n++) { + operator[](n).bind(); + } +} + +int16_t TertiaryInput::poll(unsigned n) { + return operator[](n).poll(); +} + +// + +void SecondaryInput::attach(const string &primaryName) { + for(unsigned n = 0; n < size(); n++) { + operator[](n).attach(primaryName, name); + } +} + +void SecondaryInput::bind() { + for(unsigned n = 0; n < size(); n++) { + operator[](n).bind(); + } +} + +// + +void PrimaryInput::attach() { + for(unsigned n = 0; n < size(); n++) { + operator[](n).attach(name); + } +} + +void PrimaryInput::bind() { + for(unsigned n = 0; n < size(); n++) { + operator[](n).bind(); + } +} + +// + +void InputManager::scan() { + activeScancode = !activeScancode; + input.poll(scancode[activeScancode]); + + for(unsigned n = 0; n < Scancode::Limit; n++) { + if(scancode[!activeScancode][n] != scancode[activeScancode][n]) { + if(settingsWindow->focused()) inputSettings->inputEvent(n, scancode[activeScancode][n]); + if(mainWindow->focused()) userInterface.inputEvent(n, scancode[activeScancode][n]); + } + } +} + +InputManager::InputManager() { + inputManager = this; + + inputList.append(nes); + inputList.append(snes); + inputList.append(gameBoy); + inputList.append(userInterface); + + for(unsigned n = 0; n < inputList.size(); n++) inputList[n].attach(); + config.load(application->path("input.cfg")); + config.save(application->path("input.cfg")); + for(unsigned n = 0; n < inputList.size(); n++) inputList[n].bind(); + + activeScancode = 0; +} + +InputManager::~InputManager() { + config.save(application->path("input.cfg")); +} diff --git a/ui/input/input.hpp b/ui/input/input.hpp new file mode 100755 index 00000000..ba0a5775 --- /dev/null +++ b/ui/input/input.hpp @@ -0,0 +1,73 @@ +struct AbstractInput { + enum class Type : unsigned { Button, MouseButton, MouseAxis, HatUp, HatDown, HatLeft, HatRight, Axis, AxisLo, AxisHi } type; + string name; + string mapping; + unsigned scancode; + + virtual void attach(const string &primaryName, const string &secondaryName, const string &tertiaryName); + virtual void bind(); + virtual bool bind(int16_t scancode, int16_t value) = 0; + virtual int16_t poll(); +}; + +struct AnalogInput : AbstractInput { + bool bind(int16_t scancode, int16_t value); + int16_t poll(); +}; + +struct DigitalInput : AbstractInput { + bool bind(int16_t scancode, int16_t value); + int16_t poll(); +}; + +struct TurboInput : DigitalInput { + unsigned phase; + + int16_t poll(); + TurboInput(); +}; + +struct TertiaryInput : reference_array { + string name; + + virtual void attach(const string &primaryName, const string &secondaryName); + virtual void bind(); + virtual int16_t poll(unsigned n); +}; + +struct SecondaryInput : reference_array { + string name; + + virtual void attach(const string &primaryName); + virtual void bind(); +}; + +struct PrimaryInput : reference_array { + string name; + + virtual void attach(); + virtual void bind(); +}; + +#include "nes.hpp" +#include "snes.hpp" +#include "gameboy.hpp" +#include "user-interface.hpp" + +struct InputManager { + configuration config; + int16_t scancode[2][Scancode::Limit]; + bool activeScancode; + + reference_array inputList; + NesInput nes; + SnesInput snes; + GameBoyInput gameBoy; + UserInterfaceInput userInterface; + + void scan(); + InputManager(); + ~InputManager(); +}; + +extern InputManager *inputManager; diff --git a/ui/input/nes.cpp b/ui/input/nes.cpp new file mode 100755 index 00000000..60703a0e --- /dev/null +++ b/ui/input/nes.cpp @@ -0,0 +1,60 @@ +int16_t NesGamepad::poll(unsigned n) { + switch(n) { + case 0: return a.poll() | aTurbo.poll(); + case 1: return b.poll() | bTurbo.poll(); + case 2: return select.poll(); + case 3: return start.poll(); + case 4: return up.poll() & !down.poll(); + case 5: return down.poll() & !up.poll(); + case 6: return left.poll() & !right.poll(); + case 7: return right.poll() & !left.poll(); + } + return 0; +} + +NesGamepad::NesGamepad() { + name = "Gamepad"; + + up.name = "Up"; + down.name = "Down"; + left.name = "Left"; + right.name = "Right"; + b.name = "B"; + a.name = "A"; + select.name = "Select"; + start.name = "Start"; + bTurbo.name = "Turbo B"; + aTurbo.name = "Turbo A"; + + up.mapping = "KB0::Up"; + down.mapping = "KB0::Down"; + left.mapping = "KB0::Left"; + right.mapping = "KB0::Right"; + b.mapping = "KB0::Z"; + a.mapping = "KB0::X"; + select.mapping = "KB0::Apostrophe"; + start.mapping = "KB0::Return"; + + append(up, down, left, right, b,a, select, start, bTurbo, aTurbo); +} + +// + +NesPort1Input::NesPort1Input() { + name = "Controller Port 1"; + append(gamepad); +} + +// + +NesPort2Input::NesPort2Input() { + name = "Controller Port 2"; + append(gamepad); +} + +// + +NesInput::NesInput() { + name = "NES"; + append(port1, port1); +} diff --git a/ui/input/nes.hpp b/ui/input/nes.hpp new file mode 100755 index 00000000..b3199e27 --- /dev/null +++ b/ui/input/nes.hpp @@ -0,0 +1,27 @@ +struct NesGamepad : TertiaryInput { + DigitalInput up, down, left, right; + DigitalInput b, a, select, start; + TurboInput bTurbo, aTurbo; + + int16_t poll(unsigned n); + NesGamepad(); +}; + +struct NesPort1Input : SecondaryInput { + NesGamepad gamepad; + + NesPort1Input(); +}; + +struct NesPort2Input : SecondaryInput { + NesGamepad gamepad; + + NesPort2Input(); +}; + +struct NesInput : PrimaryInput { + NesPort1Input port1; + NesPort2Input port2; + + NesInput(); +}; diff --git a/ui/input/snes.cpp b/ui/input/snes.cpp new file mode 100755 index 00000000..e08c5606 --- /dev/null +++ b/ui/input/snes.cpp @@ -0,0 +1,184 @@ +int16_t SnesGamepad::poll(unsigned n) { + switch((SNES::Input::JoypadID)n) { + case SNES::Input::JoypadID::Up: return up.poll() & !down.poll(); + case SNES::Input::JoypadID::Down: return down.poll() & !up.poll(); + case SNES::Input::JoypadID::Left: return left.poll() & !right.poll(); + case SNES::Input::JoypadID::Right: return right.poll() & !left.poll(); + case SNES::Input::JoypadID::B: return b.poll() | bTurbo.poll(); + case SNES::Input::JoypadID::A: return a.poll() | aTurbo.poll(); + case SNES::Input::JoypadID::Y: return y.poll() | yTurbo.poll(); + case SNES::Input::JoypadID::X: return x.poll() | xTurbo.poll(); + case SNES::Input::JoypadID::L: return l.poll() | lTurbo.poll(); + case SNES::Input::JoypadID::R: return r.poll() | rTurbo.poll(); + case SNES::Input::JoypadID::Select: return select.poll(); + case SNES::Input::JoypadID::Start: return start.poll(); + } + return 0; +} + +SnesGamepad::SnesGamepad(const string &name, bool defaultBindings) { + this->name = name; + + up.name = "Up", down.name = "Down", left.name = "Left", right.name = "Right"; + b.name = "B", a.name = "A", y.name = "Y", x.name = "X"; + l.name = "L", r.name = "R", select.name = "Select", start.name = "Start"; + bTurbo.name = "Turbo B", aTurbo.name = "Turbo A", yTurbo.name = "Turbo Y", xTurbo.name = "Turbo X"; + lTurbo.name = "Turbo L", rTurbo.name = "Turbo R"; + + if(defaultBindings) { + up.mapping = "KB0::Up"; + down.mapping = "KB0::Down"; + left.mapping = "KB0::Left"; + right.mapping = "KB0::Right"; + b.mapping = "KB0::Z"; + a.mapping = "KB0::X"; + y.mapping = "KB0::A"; + x.mapping = "KB0::S"; + l.mapping = "KB0::D"; + r.mapping = "KB0::C"; + select.mapping = "KB0::Apostrophe"; + start.mapping = "KB0::Return"; + } + + append(up, down, left, right, b, a, y, x, l, r, select, start); + append(bTurbo, aTurbo, yTurbo, xTurbo, lTurbo, rTurbo); +} + +// + +int16_t SnesMouse::poll(unsigned n) { + switch((SNES::Input::MouseID)n) { + case SNES::Input::MouseID::X: return xaxis.poll(); + case SNES::Input::MouseID::Y: return yaxis.poll(); + case SNES::Input::MouseID::Left: return left.poll(); + case SNES::Input::MouseID::Right: return right.poll(); + } + return 0; +} + +SnesMouse::SnesMouse(const string &name, bool defaultBindings) { + this->name = name; + + xaxis.name = "X-axis", yaxis.name = "Y-axis"; + left.name = "Left button", right.name = "Right button"; + + if(defaultBindings) { + xaxis.mapping = "MS0::Xaxis"; + yaxis.mapping = "MS0::Yaxis"; + left.mapping = "MS0::Button0"; + right.mapping = "MS0::Button2"; + } + + append(xaxis, yaxis, left, right); +} + +// + +int16_t SnesSuperScope::poll(unsigned n) { + switch((SNES::Input::SuperScopeID)n) { + case SNES::Input::SuperScopeID::X: return xaxis.poll(); + case SNES::Input::SuperScopeID::Y: return yaxis.poll(); + case SNES::Input::SuperScopeID::Trigger: return trigger.poll(); + case SNES::Input::SuperScopeID::Cursor: return cursor.poll(); + case SNES::Input::SuperScopeID::Turbo: return turbo.poll(); + case SNES::Input::SuperScopeID::Pause: return pause.poll(); + } + return 0; +} + +SnesSuperScope::SnesSuperScope(const string &name, bool defaultBindings) { + this->name = name; + + xaxis.name = "X-axis", yaxis.name = "Y-axis"; + trigger.name = "Trigger", cursor.name = "Cursor", turbo.name = "Turbo", pause.name = "Pause"; + + if(defaultBindings) { + xaxis.mapping = "MS0::Xaxis"; + yaxis.mapping = "MS0::Yaxis"; + trigger.mapping = "MS0::Button0"; + cursor.mapping = "MS0::Button2"; + turbo.mapping = "KB0::T"; + pause.mapping = "KB0::P"; + } + + append(xaxis, yaxis, trigger, cursor, turbo, pause); +} + +// + +int16_t SnesJustifier::poll(unsigned n) { + switch((SNES::Input::JustifierID)n) { + case SNES::Input::JustifierID::X: return xaxis.poll(); + case SNES::Input::JustifierID::Y: return yaxis.poll(); + case SNES::Input::JustifierID::Trigger: return trigger.poll(); + case SNES::Input::JustifierID::Start: return start.poll(); + } + return 0; +} + +SnesJustifier::SnesJustifier(const string &name, bool defaultBindings) { + this->name = name; + + xaxis.name = "X-axis", yaxis.name = "Y-axis"; + trigger.name = "Trigger", start.name = "Start"; + + if(defaultBindings) { + xaxis.mapping = "MS0::Xaxis"; + yaxis.mapping = "MS0::Yaxis"; + trigger.mapping = "MS0::Button0"; + start.mapping = "MS0::Button2"; + } + + append(xaxis, yaxis, trigger, start); +} + +// + +SnesPort1Input::SnesPort1Input(): +gamepad("Gamepad", true), +multitap1("Multitap - Port 1", false), +multitap2("Multitap - Port 2", false), +multitap3("Multitap - Port 3", false), +multitap4("Multitap - Port 4", false), +mouse("Mouse", true) +{ + name = "Controller Port 1"; + append(gamepad); + append(multitap1); + append(multitap2); + append(multitap3); + append(multitap4); + append(mouse); +} + +// + +SnesPort2Input::SnesPort2Input(): +gamepad("Gamepad", false), +multitap1("Multitap - Port 1", false), +multitap2("Multitap - Port 2", false), +multitap3("Multitap - Port 3", false), +multitap4("Multitap - Port 4", false), +mouse("Mouse", true), +superScope("Super Scope", true), +justifier1("Justifier - Port 1", true), +justifier2("Justifier - Port 2", false) +{ + name = "Controller Port 2"; + append(gamepad); + append(multitap1); + append(multitap2); + append(multitap3); + append(multitap4); + append(mouse); + append(superScope); + append(justifier1); + append(justifier2); +} + +// + +SnesInput::SnesInput() { + name = "SNES"; + append(port1, port2); +} diff --git a/ui/input/snes.hpp b/ui/input/snes.hpp new file mode 100755 index 00000000..a9e343a2 --- /dev/null +++ b/ui/input/snes.hpp @@ -0,0 +1,66 @@ +struct SnesGamepad : TertiaryInput { + DigitalInput up, down, left, right; + DigitalInput b, a, y, x; + DigitalInput l, r, select, start; + TurboInput bTurbo, aTurbo, yTurbo, xTurbo; + TurboInput lTurbo, rTurbo; + + int16_t poll(unsigned n); + SnesGamepad(const string &name, bool defaultBindings); +}; + +struct SnesMouse : TertiaryInput { + AnalogInput xaxis, yaxis; + DigitalInput left, right; + + int16_t poll(unsigned n); + SnesMouse(const string &name, bool defaultBindings); +}; + +struct SnesSuperScope : TertiaryInput { + AnalogInput xaxis, yaxis; + DigitalInput trigger, cursor, turbo, pause; + + int16_t poll(unsigned n); + SnesSuperScope(const string &name, bool defaultBindings); +}; + +struct SnesJustifier : TertiaryInput { + AnalogInput xaxis, yaxis; + DigitalInput trigger, start; + + int16_t poll(unsigned n); + SnesJustifier(const string &name, bool defaultBindings); +}; + +struct SnesPort1Input : SecondaryInput { + SnesGamepad gamepad; + SnesGamepad multitap1; + SnesGamepad multitap2; + SnesGamepad multitap3; + SnesGamepad multitap4; + SnesMouse mouse; + + SnesPort1Input(); +}; + +struct SnesPort2Input : SecondaryInput { + SnesGamepad gamepad; + SnesGamepad multitap1; + SnesGamepad multitap2; + SnesGamepad multitap3; + SnesGamepad multitap4; + SnesMouse mouse; + SnesSuperScope superScope; + SnesJustifier justifier1; + SnesJustifier justifier2; + + SnesPort2Input(); +}; + +struct SnesInput : PrimaryInput { + SnesPort1Input port1; + SnesPort2Input port2; + + SnesInput(); +}; diff --git a/ui/input/user-interface.cpp b/ui/input/user-interface.cpp new file mode 100755 index 00000000..90ce26d2 --- /dev/null +++ b/ui/input/user-interface.cpp @@ -0,0 +1,116 @@ +void HotkeyGeneral::inputEvent(int16_t scancode, int16_t value) { + if(scancode == saveState.scancode && value) { + interface->saveState(activeSlot); + } + + if(scancode == loadState.scancode && value) { + interface->loadState(activeSlot); + } + + if(scancode == decrementSlot.scancode && value) { + if(--activeSlot == 0) activeSlot = 5; + utility->showMessage({ "Selected slot ", activeSlot }); + } + + if(scancode == incrementSlot.scancode && value) { + if(++activeSlot == 6) activeSlot = 1; + utility->showMessage({ "Selected slot ", activeSlot }); + } + + if(scancode == toggleMouseCapture.scancode && value) { + if(mainWindow->fullScreen() == false) { + input.acquired() ? input.unacquire() : input.acquire(); + } + } + + if(scancode == toggleFullScreen.scancode && value) { + utility->toggleFullScreen(); + } + + if(scancode == pause.scancode && value) { + application->pause = !application->pause; + } + + if(scancode == turboMode.scancode) { + if(value) { + video.set(Video::Synchronize, false); + audio.set(Audio::Synchronize, false); + } else { + video.set(Video::Synchronize, config->video.synchronize); + audio.set(Audio::Synchronize, config->audio.synchronize); + } + } + + if(scancode == power.scancode && value) { + interface->power(); + } + + if(scancode == reset.scancode && value) { + interface->reset(); + } + + if(scancode == quit.scancode && value) { + application->quit = true; + } +} + +HotkeyGeneral::HotkeyGeneral() { + name = "General"; + + saveState.name = "Save state"; + loadState.name = "Load state"; + decrementSlot.name = "Decrement state slot"; + incrementSlot.name = "Increment state slot"; + toggleMouseCapture.name = "Toggle mouse capture"; + toggleFullScreen.name = "Toggle fullscreen"; + pause.name = "Pause emulation"; + turboMode.name = "Turbo mode"; + power.name = "Power cycle"; + reset.name = "Reset"; + quit.name = "Close emulator"; + + saveState.mapping = "KB0::F5"; + loadState.mapping = "KB0::F7"; + decrementSlot.mapping = "KB0::F6"; + incrementSlot.mapping = "KB0::F8"; + toggleMouseCapture.mapping = "KB0::F12"; + toggleFullScreen.mapping = "KB0::F11"; + pause.mapping = "KB0::P"; + turboMode.mapping = "KB0::Tilde"; + + append(saveState); + append(loadState); + append(decrementSlot); + append(incrementSlot); + append(toggleMouseCapture); + append(toggleFullScreen); + append(pause); + append(turboMode); + append(power); + append(reset); + append(quit); + + activeSlot = 1; +} + +// + +void HotkeyInput::inputEvent(int16_t scancode, int16_t value) { + general.inputEvent(scancode, value); +} + +HotkeyInput::HotkeyInput() { + name = "Hotkeys"; + append(general); +} + +// + +void UserInterfaceInput::inputEvent(int16_t scancode, int16_t value) { + hotkey.inputEvent(scancode, value); +} + +UserInterfaceInput::UserInterfaceInput() { + name = "User Interface"; + append(hotkey); +} diff --git a/ui/input/user-interface.hpp b/ui/input/user-interface.hpp new file mode 100755 index 00000000..62134c2d --- /dev/null +++ b/ui/input/user-interface.hpp @@ -0,0 +1,33 @@ +struct HotkeyGeneral : TertiaryInput { + DigitalInput saveState; + DigitalInput loadState; + DigitalInput decrementSlot; + DigitalInput incrementSlot; + DigitalInput toggleMouseCapture; + DigitalInput toggleFullScreen; + DigitalInput pause; + DigitalInput turboMode; + DigitalInput power; + DigitalInput reset; + DigitalInput quit; + + void inputEvent(int16_t scancode, int16_t value); + HotkeyGeneral(); + +private: + unsigned activeSlot; +}; + +struct HotkeyInput : SecondaryInput { + HotkeyGeneral general; + + void inputEvent(int16_t scancode, int16_t value); + HotkeyInput(); +}; + +struct UserInterfaceInput : PrimaryInput { + HotkeyInput hotkey; + + void inputEvent(int16_t scancode, int16_t value); + UserInterfaceInput(); +}; diff --git a/ui/interface/gameboy/gameboy.cpp b/ui/interface/gameboy/gameboy.cpp new file mode 100755 index 00000000..dc26ec6e --- /dev/null +++ b/ui/interface/gameboy/gameboy.cpp @@ -0,0 +1,111 @@ +void InterfaceGameBoy::initialize() { + GameBoy::interface = this; + GameBoy::system.init(); +} + +bool InterfaceGameBoy::cartridgeLoaded() { + return GameBoy::cartridge.loaded(); +} + +bool InterfaceGameBoy::loadCartridge(GameBoy::System::Revision revision, const string &filename) { + uint8_t *data; + unsigned size; + if(interface->loadFile(filename, data, size) == false) return false; + + interface->unloadCartridge(); + interface->baseName = nall::basename(filename); + + GameBoyCartridge info(data, size); + GameBoy::cartridge.load(revision, info.markup, data, size); + GameBoy::system.power(); + delete[] data; + + if(GameBoy::cartridge.ramsize) { + filemap fp; + if(fp.open(string{ interface->baseName, ".sav" }, filemap::mode::read)) { + memcpy(GameBoy::cartridge.ramdata, fp.data(), min(GameBoy::cartridge.ramsize, fp.size())); + } + } + + GameBoy::interface = this; + GameBoy::video.generate(GameBoy::Video::Format::RGB24); + interface->loadCartridge(::Interface::Mode::GameBoy); + return true; +} + +void InterfaceGameBoy::unloadCartridge() { + if(GameBoy::cartridge.ramsize) { + file::write({ interface->baseName, ".sav" }, GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize); + } + + GameBoy::cartridge.unload(); + interface->baseName = ""; +} + +void InterfaceGameBoy::power() { + GameBoy::system.power(); +} + +void InterfaceGameBoy::reset() { + GameBoy::system.power(); //Game Boy lacks reset button +} + +void InterfaceGameBoy::run() { + do { + GameBoy::system.run(); + } while(GameBoy::scheduler.exit_reason() != GameBoy::Scheduler::ExitReason::FrameEvent); +} + +serializer InterfaceGameBoy::serialize() { + GameBoy::system.runtosave(); + return GameBoy::system.serialize(); +} + +bool InterfaceGameBoy::unserialize(serializer &s) { + return GameBoy::system.unserialize(s); +} + +void InterfaceGameBoy::setCheats(const lstring &list) { + GameBoy::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data, comp; + if(GameBoy::Cheat::decode(part, addr, data, comp)) { + GameBoy::cheat.append({ addr, data, comp }); + } + } + } + GameBoy::cheat.synchronize(); +} + +// + +void InterfaceGameBoy::videoRefresh(const uint16_t *data) { + static uint32_t output[160 * 144]; + + for(unsigned y = 0; y < 144; y++) { + const uint16_t *sp = data + y * 160; + uint32_t *dp = output + y * 160; + for(unsigned x = 0; x < 160; x++) { + uint16_t color = *sp++; + *dp++ = GameBoy::video.palette[color]; + } + } + + interface->videoRefresh(output, 160 * sizeof(uint32_t), 160, 144); +} + +void InterfaceGameBoy::audioSample(int16_t csample, int16_t lsample, int16_t rsample) { + signed samples[] = { lsample, rsample }; + dspaudio.sample(samples); + while(dspaudio.pending()) { + dspaudio.read(samples); + audio.sample(samples[0], samples[1]); + } +} + +bool InterfaceGameBoy::inputPoll(unsigned id) { + return inputManager->gameBoy.device.controller.poll(id); +} diff --git a/ui/interface/gameboy/gameboy.hpp b/ui/interface/gameboy/gameboy.hpp new file mode 100755 index 00000000..3b4b0d0e --- /dev/null +++ b/ui/interface/gameboy/gameboy.hpp @@ -0,0 +1,20 @@ +struct InterfaceGameBoy : InterfaceCore, GameBoy::Interface { + void initialize(); + + bool cartridgeLoaded(); + bool loadCartridge(GameBoy::System::Revision revision, const string &filename); + void unloadCartridge(); + + void power(); + void reset(); + void run(); + + serializer serialize(); + bool unserialize(serializer&); + + void setCheats(const lstring &list = lstring{}); + + void videoRefresh(const uint16_t *data); + void audioSample(int16_t csample, int16_t lsample, int16_t rsample); + bool inputPoll(unsigned id); +}; diff --git a/ui/interface/interface.cpp b/ui/interface/interface.cpp new file mode 100755 index 00000000..3c714e97 --- /dev/null +++ b/ui/interface/interface.cpp @@ -0,0 +1,252 @@ +#include "../base.hpp" +#include "palette.cpp" +#include "nes/nes.cpp" +#include "snes/snes.cpp" +#include "gameboy/gameboy.cpp" +Interface *interface = nullptr; + +Filter filter; + +void Filter::render(const uint32_t *input, unsigned inputPitch, unsigned inputWidth, unsigned inputHeight) { + width = inputWidth, height = inputHeight; + dl_size(width, height); + dl_render(data, pitch, input, inputPitch, inputWidth, inputHeight); +} + +Filter::Filter() { + data = new uint32_t[2048 * 2048]; + pitch = 2048 * sizeof(uint32_t); +} + +Filter::~Filter() { + delete[] data; +} + +void Interface::bindControllers() { + switch(mode()) { + case Mode::NES: + nes.setController(0, config->nes.controllerPort1Device); + nes.setController(1, config->nes.controllerPort2Device); + break; + + case Mode::SNES: + snes.setController(0, config->snes.controllerPort1Device); + snes.setController(1, config->snes.controllerPort2Device); + break; + } +} + +void Interface::setController(unsigned port, unsigned device) { + switch(mode()) { + case Mode::NES: return nes.setController(port, device); + case Mode::SNES: return snes.setController(port, device); + } +} + +void Interface::updateDSP() { + audio.set(Audio::Frequency, config->audio.frequency); + audio.set(Audio::Latency, config->audio.latency); + + if(config->audio.resampler == "linear" ) dspaudio.setResampler(DSP::ResampleEngine::Linear); + if(config->audio.resampler == "hermite") dspaudio.setResampler(DSP::ResampleEngine::Hermite); + if(config->audio.resampler == "sinc" ) dspaudio.setResampler(DSP::ResampleEngine::Sinc); + dspaudio.setResamplerFrequency(config->audio.frequency); + dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0); + + switch(mode()) { + case Mode::NES: return dspaudio.setFrequency(config->audio.frequencyNES); + case Mode::SNES: return dspaudio.setFrequency(config->audio.frequencySNES); + case Mode::GameBoy: return dspaudio.setFrequency(config->audio.frequencyGameBoy); + } +} + +bool Interface::cartridgeLoaded() { + switch(mode()) { + case Mode::NES: return nes.cartridgeLoaded(); + case Mode::SNES: return snes.cartridgeLoaded(); + case Mode::GameBoy: return gameBoy.cartridgeLoaded(); + } + return false; +} + +void Interface::loadCartridge(Mode mode) { + utility->setMode(this->mode = mode); + switch(mode) { + case Mode::NES: core = &nes; break; + case Mode::SNES: core = &snes; break; + case Mode::GameBoy: core = &gameBoy; break; + default: core = nullptr; break; + } + + bindControllers(); + cheatEditor->load({ baseName, ".cht" }); + stateManager->load({ baseName, ".bsa" }, 0u); + dipSwitches->load(); + utility->showMessage({ "Loaded ", notdir(baseName) }); +} + +bool Interface::loadCartridge(const string &filename) { + bool result = false; + if(filename.endswith(".nes")) result = nes.loadCartridge(filename); + if(filename.endswith(".sfc")) result = snes.loadCartridge(filename); + if(filename.endswith(".gb" )) result = gameBoy.loadCartridge(GameBoy::System::Revision::GameBoy, filename); + if(filename.endswith(".gbc")) result = gameBoy.loadCartridge(GameBoy::System::Revision::GameBoyColor, filename); + return result; +} + +void Interface::unloadCartridge() { + if(cartridgeLoaded() == false) return; + cheatDatabase->setVisible(false); + cheatEditor->save({ baseName, ".cht" }); + stateManager->save({ baseName, ".bsa" }, 0u); + setCheatCodes(); + + switch(mode()) { + case Mode::NES: nes.unloadCartridge(); break; + case Mode::SNES: snes.unloadCartridge(); break; + case Mode::GameBoy: gameBoy.unloadCartridge(); break; + } + + interface->baseName = ""; + interface->slotName.reset(); + utility->setMode(mode = Mode::None); +} + +void Interface::power() { + if(core == nullptr) return; + core->power(); + utility->showMessage("System power was cycled"); +} + +void Interface::reset() { + if(core == nullptr) return; + core->reset(); + utility->showMessage("System was reset"); +} + +void Interface::run() { + if(core == nullptr) return; + core->run(); +} + +serializer Interface::serialize() { + if(core == nullptr) return serializer(); + return core->serialize(); +} + +bool Interface::unserialize(serializer &s) { + if(core == nullptr) return false; + return core->unserialize(s); +} + +bool Interface::saveState(unsigned slot) { + string filename = { baseName, "-", slot, ".bst" }; + serializer s = serialize(); + bool result = file::write(filename, s.data(), s.size()); + utility->showMessage(result == true ? string{ "Saved state ", slot } : "Failed to save state"); + return result; +} + +bool Interface::loadState(unsigned slot) { + string filename = { baseName, "-", slot, ".bst" }; + uint8_t *data; + unsigned size; + if(file::read(filename, data, size) == false) { + utility->showMessage(string{ "Slot ", slot, " save file not found" }); + return false; + } + serializer s(data, size); + bool result = unserialize(s); + utility->showMessage(result == true ? string{ "Loaded state ", slot } : "Failed to load state"); + return result; +} + +void Interface::setCheatCodes(const lstring &list) { + switch(mode()) { + case Mode::NES: return nes.setCheats(list); + case Mode::SNES: return snes.setCheats(list); + case Mode::GameBoy: return gameBoy.setCheats(list); + } +} + +string Interface::sha256() { + switch(mode()) { + case Mode::NES: return NES::cartridge.sha256(); + case Mode::SNES: return SNES::cartridge.sha256(); + case Mode::GameBoy: return GameBoy::cartridge.sha256(); + } + return "{None}"; +} + +Interface::Interface() : core(nullptr) { + mode = Mode::None; + palette.update(); + nes.initialize(); + snes.initialize(); + gameBoy.initialize(); +} + +//internal + +bool Interface::loadFile(const string &filename, uint8_t *&data, unsigned &size) { + if(file::read(filename, data, size) == false) return false; + + string patchname = { nall::basename(filename), ".bps" }; + if(file::exists(patchname) == false) return true; + + bpspatch bps; + bps.modify(patchname); + bps.source(data, size); + unsigned targetSize = bps.size(); + uint8_t *targetData = new uint8_t[targetSize]; + bps.target(targetData, targetSize); + if(bps.apply() != bpspatch::result::success) { + delete[] targetData; + return true; + } + + delete[] data; + data = targetData; + size = targetSize; + return true; +} + +void Interface::videoRefresh(const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height) { + uint32_t *output; + unsigned outputPitch; + + if(filter.opened()) { + filter.render(input, inputPitch, width, height); + input = filter.data; + inputPitch = filter.pitch; + width = filter.width; + height = filter.height; + } + + if(video.lock(output, outputPitch, width, height)) { + inputPitch >>= 2, outputPitch >>= 2; + + for(unsigned y = 0; y < height; y++) { + const uint32_t *sp = input + y * inputPitch; + uint32_t *dp = output + y * outputPitch; + for(unsigned x = 0; x < width; x++) { + uint32_t color = *sp++; + *dp++ = (palette[color >> 16] << 16) + (palette[color >> 8] << 8) + (palette[color >> 0] << 0); + } + } + + video.unlock(); + video.refresh(); + } + + static unsigned frameCounter = 0; + static time_t previous, current; + frameCounter++; + + time(¤t); + if(current != previous) { + previous = current; + utility->setStatusText({ "FPS: ", frameCounter }); + frameCounter = 0; + } +} diff --git a/ui/interface/interface.hpp b/ui/interface/interface.hpp new file mode 100755 index 00000000..2b87b02b --- /dev/null +++ b/ui/interface/interface.hpp @@ -0,0 +1,70 @@ +#include "palette.hpp" + +struct InterfaceCore { + virtual void power() = 0; + virtual void reset() = 0; + virtual void run() = 0; + + virtual serializer serialize() = 0; + virtual bool unserialize(serializer&) = 0; +}; + +#include "nes/nes.hpp" +#include "snes/snes.hpp" +#include "gameboy/gameboy.hpp" + +struct Filter : public library { + function dl_size; + function dl_render; + void render(const uint32_t*, unsigned, unsigned, unsigned); + Filter(); + ~Filter(); + + uint32_t *data; + unsigned pitch; + unsigned width; + unsigned height; +}; + +extern Filter filter; + +struct Interface : property { + enum class Mode : unsigned { None, SNES, NES, GameBoy }; + readonly mode; + + void bindControllers(); + void setController(unsigned port, unsigned device); + void updateDSP(); + + bool cartridgeLoaded(); + void loadCartridge(Mode mode); + bool loadCartridge(const string &filename); //auto-detect system-type based on file extension + void unloadCartridge(); + + void power(); + void reset(); + void run(); + + serializer serialize(); + bool unserialize(serializer&); + + bool saveState(unsigned slot); + bool loadState(unsigned slot); + void setCheatCodes(const lstring &list = lstring{}); + string sha256(); + + Interface(); + + bool loadFile(const string &filename, uint8_t *&data, unsigned &size); + void videoRefresh(const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height); + + string baseName; // = "/path/to/cartridge" (no extension) + lstring slotName; + + InterfaceCore *core; + InterfaceNES nes; + InterfaceSNES snes; + InterfaceGameBoy gameBoy; +}; + +extern Interface *interface; diff --git a/ui/interface/nes/nes.cpp b/ui/interface/nes/nes.cpp new file mode 100755 index 00000000..611656d8 --- /dev/null +++ b/ui/interface/nes/nes.cpp @@ -0,0 +1,146 @@ +void InterfaceNES::initialize() { + NES::interface = this; + NES::system.init(); +} + +void InterfaceNES::setController(bool port, unsigned device) { + if(port == 0) config->nes.controllerPort1Device = device; + if(port == 1) config->nes.controllerPort2Device = device; + + if(port == 0) switch(device) { + case 0: return NES::input.connect(0, NES::Input::Device::None); + case 1: return NES::input.connect(0, NES::Input::Device::Joypad); + } + + if(port == 1) switch(device) { + case 0: return NES::input.connect(1, NES::Input::Device::None); + case 1: return NES::input.connect(1, NES::Input::Device::Joypad); + } +} + +bool InterfaceNES::cartridgeLoaded() { + return NES::cartridge.loaded(); +} + +bool InterfaceNES::loadCartridge(const string &filename) { + uint8_t *data; + unsigned size; + if(interface->loadFile(filename, data, size) == false) return false; + + interface->unloadCartridge(); + interface->baseName = nall::basename(filename); + + string markup; + markup.readfile({ interface->baseName, ".bml" }); + + NES::cartridge.load(markup, data, size); + NES::system.power(); + delete[] data; + + if(NES::cartridge.ram_size()) { + filemap fp; + if(fp.open(string{ interface->baseName, ".sav" }, filemap::mode::read)) { + memcpy(NES::cartridge.ram_data(), fp.data(), min(NES::cartridge.ram_size(), fp.size())); + } + } + + interface->loadCartridge(::Interface::Mode::NES); + NES::video.generate(NES::Video::Format::RGB24); + return true; +} + +void InterfaceNES::unloadCartridge() { + if(NES::cartridge.ram_size()) { + file::write({ interface->baseName, ".sav" }, NES::cartridge.ram_data(), NES::cartridge.ram_size()); + } + NES::cartridge.unload(); + interface->baseName = ""; +} + +// + +void InterfaceNES::power() { + NES::system.power(); +} + +void InterfaceNES::reset() { + NES::system.reset(); +} + +void InterfaceNES::run() { + NES::system.run(); +} + +// + +serializer InterfaceNES::serialize() { + NES::system.runtosave(); + return NES::system.serialize(); +} + +bool InterfaceNES::unserialize(serializer &s) { + return NES::system.unserialize(s); +} + +// + +void InterfaceNES::setCheats(const lstring &list) { + NES::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data, comp; + if(NES::Cheat::decode(part, addr, data, comp)) { + NES::cheat.append({ addr, data, comp }); + } + } + } + NES::cheat.synchronize(); +} + +// + +void InterfaceNES::videoRefresh(const uint16_t *data) { + static uint32_t output[256 * 240]; + + for(unsigned y = 0; y < 240; y++) { + const uint16_t *sp = data + y * 256; + uint32_t *dp = output + y * 256; + for(unsigned x = 0; x < 256; x++) { + uint32_t color = *sp++; + *dp++ = NES::video.palette[color]; + } + } + + if(config->video.maskOverscan) { + unsigned osw = config->video.maskOverscanHorizontal; + unsigned osh = config->video.maskOverscanVertical; + + for(unsigned y = 0; y < 240; y++) { + uint32_t *dp = output + y * 256; + if(y < osh || y >= 240 - osh) { + memset(dp, 0, 256 * sizeof(uint32_t)); + } else { + memset(dp + 0, 0, osw * sizeof(uint32_t)); + memset(dp + 256 - osw, 0, osw * sizeof(uint32_t)); + } + } + } + + interface->videoRefresh(output, 256 * sizeof(uint32_t), 256, 240); +} + +void InterfaceNES::audioSample(int16_t sample) { + signed samples[] = { sample }; + dspaudio.sample(samples); + while(dspaudio.pending()) { + dspaudio.read(samples); + audio.sample(samples[0], samples[0]); //NES audio output is monaural; ruby only takes stereo audio + } +} + +int16_t InterfaceNES::inputPoll(bool port, unsigned device, unsigned id) { + if(port == 0 && device == 0) return inputManager->nes.port1.gamepad.poll(id); + return 0; +} diff --git a/ui/interface/nes/nes.hpp b/ui/interface/nes/nes.hpp new file mode 100755 index 00000000..1584bfbc --- /dev/null +++ b/ui/interface/nes/nes.hpp @@ -0,0 +1,21 @@ +struct InterfaceNES : InterfaceCore, NES::Interface { + void initialize(); + void setController(bool port, unsigned device); + + bool cartridgeLoaded(); + bool loadCartridge(const string &filename); + void unloadCartridge(); + + void power(); + void reset(); + void run(); + + serializer serialize(); + bool unserialize(serializer&); + + void setCheats(const lstring &list = lstring{}); + + void videoRefresh(const uint16_t *data); + void audioSample(int16_t sample); + int16_t inputPoll(bool port, unsigned device, unsigned id); +}; diff --git a/ui/interface/palette.cpp b/ui/interface/palette.cpp new file mode 100755 index 00000000..c030dd62 --- /dev/null +++ b/ui/interface/palette.cpp @@ -0,0 +1,47 @@ +Palette palette; + +uint8_t Palette::operator[](uint8_t n) { + return color[n]; +} + +/* 5-bit -> 8-bit +const uint8_t Palette::gammaRamp[32] = { + 0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c, + 0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78, + 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0, + 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff, +}; +*/ + +uint8_t Palette::contrastAdjust(uint8_t input) { + signed contrast = config->video.contrast - 100; + signed result = input - contrast + (2 * contrast * input + 127) / 255; + return max(0, min(255, result)); +} + +uint8_t Palette::brightnessAdjust(uint8_t input) { + signed brightness = config->video.brightness - 100; + signed result = input + brightness; + return max(0, min(255, result)); +} + +uint8_t Palette::gammaAdjust(uint8_t input) { + signed result = (signed)(pow(((double)input / 255.0), (double)config->video.gamma / 100.0) * 255.0 + 0.5); + return max(0, min(255, result)); +} + +void Palette::update() { + double exponent = 1.0 + (double)config->video.gamma * 0.01; + for(unsigned n = 0; n < 256; n++) { + unsigned result = (n < 128 ? 127 * pow(((double)n / 127), exponent) : n); + color[n] = result; + } + + for(unsigned n = 0; n < 256; n++) { + color[n] = contrastAdjust(color[n]); + } + + for(unsigned n = 0; n < 256; n++) { + color[n] = brightnessAdjust(color[n]); + } +} diff --git a/ui/interface/palette.hpp b/ui/interface/palette.hpp new file mode 100755 index 00000000..c8f8a19f --- /dev/null +++ b/ui/interface/palette.hpp @@ -0,0 +1,13 @@ +struct Palette { + alwaysinline uint8_t operator[](uint8_t color); + + uint8_t contrastAdjust(uint8_t); + uint8_t brightnessAdjust(uint8_t); + uint8_t gammaAdjust(uint8_t); + void update(); + +private: + uint32_t color[256]; +}; + +extern Palette palette; diff --git a/ui/interface/snes/snes.cpp b/ui/interface/snes/snes.cpp new file mode 100755 index 00000000..51d444db --- /dev/null +++ b/ui/interface/snes/snes.cpp @@ -0,0 +1,354 @@ +void InterfaceSNES::initialize() { + SNES::interface = this; + SNES::system.init(); +} + +void InterfaceSNES::setController(bool port, unsigned device) { + if(port == 0) config->snes.controllerPort1Device = device; + if(port == 1) config->snes.controllerPort2Device = device; + + if(port == 0) switch(device) { + case 0: return SNES::input.connect(0, SNES::Input::Device::None); + case 1: return SNES::input.connect(0, SNES::Input::Device::Joypad); + case 2: return SNES::input.connect(0, SNES::Input::Device::Multitap); + case 3: return SNES::input.connect(0, SNES::Input::Device::Mouse); + } + + if(port == 1) switch(device) { + case 0: return SNES::input.connect(1, SNES::Input::Device::None); + case 1: return SNES::input.connect(1, SNES::Input::Device::Joypad); + case 2: return SNES::input.connect(1, SNES::Input::Device::Multitap); + case 3: return SNES::input.connect(1, SNES::Input::Device::Mouse); + case 4: return SNES::input.connect(1, SNES::Input::Device::SuperScope); + case 5: return SNES::input.connect(1, SNES::Input::Device::Justifier); + case 6: return SNES::input.connect(1, SNES::Input::Device::Justifiers); + case 7: return SNES::input.connect(1, SNES::Input::Device::Serial); + } +} + +bool InterfaceSNES::cartridgeLoaded() { + return SNES::cartridge.loaded(); +} + +bool InterfaceSNES::loadCartridge(const string &basename) { + uint8_t *data; + unsigned size; + if(interface->loadFile(basename, data, size) == false) return false; + + interface->unloadCartridge(); + interface->baseName = nall::basename(basename); + interface->slotName = { nall::basename(basename) }; + + string markup; + markup.readfile({ interface->baseName, ".bml" }); + if(markup == "") markup = SnesCartridge(data, size).markup; + + SNES::cartridge.rom.copy(data, size); + SNES::cartridge.load(SNES::Cartridge::Mode::Normal, markup); + SNES::system.power(); + + delete[] data; + + loadMemory(); + interface->loadCartridge(::Interface::Mode::SNES); + SNES::video.generate(SNES::Video::Format::RGB24); + return true; +} + +bool InterfaceSNES::loadSatellaviewSlottedCartridge(const string &basename, const string &slotname) { + uint8_t *data[2]; + unsigned size[2]; + if(interface->loadFile(basename, data[0], size[0]) == false) return false; + interface->loadFile(slotname, data[1], size[1]); + + interface->unloadCartridge(); + interface->baseName = nall::basename(basename); + if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname))); + interface->slotName = { nall::basename(basename), nall::basename(slotname) }; + + string markup; + markup.readfile({ interface->baseName, ".bml" }); + if(markup == "") markup = SnesCartridge(data[0], size[0]).markup; + + SNES::cartridge.rom.copy(data[0], size[0]); + if(data[1]) SNES::bsxflash.memory.copy(data[1], size[1]); + SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, markup); + SNES::system.power(); + + delete[] data[0]; + if(data[1]) delete[] data[1]; + + loadMemory(); + interface->loadCartridge(::Interface::Mode::SNES); + SNES::video.generate(SNES::Video::Format::RGB24); + return true; +} + +bool InterfaceSNES::loadSatellaviewCartridge(const string &basename, const string &slotname) { + uint8_t *data[2]; + unsigned size[2]; + if(interface->loadFile(basename, data[0], size[0]) == false) return false; + interface->loadFile(slotname, data[1], size[1]); + + interface->unloadCartridge(); + interface->baseName = nall::basename(basename); + if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname))); + interface->slotName = { nall::basename(basename), nall::basename(slotname) }; + + string markup; + markup.readfile({ interface->baseName, ".bml" }); + if(markup == "") markup = SnesCartridge(data[0], size[0]).markup; + + SNES::cartridge.rom.copy(data[0], size[0]); + if(data[1]) SNES::bsxflash.memory.copy(data[1], size[1]); + SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, markup); + SNES::system.power(); + + delete[] data[0]; + if(data[1]) delete[] data[1]; + + loadMemory(); + interface->loadCartridge(::Interface::Mode::SNES); + SNES::video.generate(SNES::Video::Format::RGB24); + return true; +} + +bool InterfaceSNES::loadSufamiTurboCartridge(const string &basename, const string &slotAname, const string &slotBname) { + uint8_t *data[3]; + unsigned size[3]; + if(interface->loadFile(basename, data[0], size[0]) == false) return false; + interface->loadFile(slotAname, data[1], size[1]); + interface->loadFile(slotBname, data[2], size[2]); + + interface->unloadCartridge(); + interface->baseName = nall::basename(basename); + if(data[1] && data[2]) interface->baseName = { nall::basename(slotAname), "+", nall::basename(notdir(slotBname)) }; + else if(data[1]) interface->baseName = nall::basename(slotAname); + else if(data[2]) interface->baseName = nall::basename(slotBname); + interface->slotName = { nall::basename(basename), nall::basename(slotAname), nall::basename(slotBname) }; + + string markup; + markup.readfile({ interface->baseName, ".bml" }); + if(markup == "") markup = SnesCartridge(data[0], size[0]).markup; + + SNES::cartridge.rom.copy(data[0], size[0]); + if(data[1]) SNES::sufamiturbo.slotA.rom.copy(data[1], size[1]); + if(data[2]) SNES::sufamiturbo.slotB.rom.copy(data[1], size[1]); + SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, markup); + SNES::system.power(); + + delete[] data[0]; + if(data[1]) delete[] data[1]; + if(data[2]) delete[] data[2]; + + loadMemory(); + interface->loadCartridge(::Interface::Mode::SNES); + SNES::video.generate(SNES::Video::Format::RGB24); + return true; +} + +bool InterfaceSNES::loadSuperGameBoyCartridge(const string &basename, const string &slotname) { + uint8_t *data[2]; + unsigned size[2]; + if(interface->loadFile(basename, data[0], size[0]) == false) return false; + interface->loadFile(slotname, data[1], size[1]); + + interface->unloadCartridge(); + interface->baseName = nall::basename(basename); + if(data[1]) interface->baseName = nall::basename(slotname); + interface->slotName = { nall::basename(basename), nall::basename(slotname) }; + + string markup; + markup.readfile({ interface->baseName, ".bml" }); + if(markup == "") markup = SnesCartridge(data[0], size[0]).markup; + + string gbMarkup; + gbMarkup.readfile({ nall::basename(slotname), ".bml" }); + if(gbMarkup == "") gbMarkup = GameBoyCartridge(data[1], size[1]).markup; + + SNES::cartridge.rom.copy(data[0], size[0]); + GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, gbMarkup, data[1], size[1]); + SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, markup); + SNES::system.power(); + + delete[] data[0]; + if(data[1]) delete[] data[1]; + + loadMemory(); + interface->loadCartridge(::Interface::Mode::SNES); + SNES::video.generate(SNES::Video::Format::RGB24); + return true; +} + +void InterfaceSNES::unloadCartridge() { + saveMemory(); + SNES::cartridge.unload(); + interface->baseName = ""; +} + +void InterfaceSNES::power() { + SNES::system.power(); +} + +void InterfaceSNES::reset() { + SNES::system.reset(); +} + +void InterfaceSNES::run() { + SNES::system.run(); +} + +//slot[] array = Cartridge::Slot to slot# conversion: +//{ Base, Bsx, SufamiTurbo, SufamiTurboA, SufamiTurboB, GameBoy } + +void InterfaceSNES::loadMemory() { + static unsigned slot[] = { 0, 0, 0, 1, 2, 1 }; + for(auto &memory : SNES::cartridge.nvram) { + if(memory.size == 0) continue; + string filename = { interface->slotName[slot[(unsigned)memory.slot]], memory.id }; + uint8_t *data; + unsigned size; + if(file::read(filename, data, size)) { + memcpy(memory.data, data, min(memory.size, size)); + delete[] data; + } + } +} + +void InterfaceSNES::saveMemory() { + static unsigned slot[] = { 0, 0, 0, 1, 2, 1 }; + for(auto &memory : SNES::cartridge.nvram) { + if(memory.size == 0) continue; + string filename = { interface->slotName[slot[(unsigned)memory.slot]], memory.id }; + file::write(filename, memory.data, memory.size); + } +} + +serializer InterfaceSNES::serialize() { + SNES::system.runtosave(); + return SNES::system.serialize(); +} + +bool InterfaceSNES::unserialize(serializer &s) { + return SNES::system.unserialize(s); +} + +void InterfaceSNES::setCheats(const lstring &list) { + if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { + GameBoy::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data, comp; + if(GameBoy::Cheat::decode(part, addr, data, comp)) { + GameBoy::cheat.append({ addr, data, comp }); + } + } + } + GameBoy::cheat.synchronize(); + return; + } + + SNES::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data; + if(SNES::Cheat::decode(part, addr, data)) { + SNES::cheat.append({ addr, data }); + } + } + } + SNES::cheat.synchronize(); +} + +// + +void InterfaceSNES::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) { + static uint32_t output[512 * 480]; + + unsigned width = 256 << hires; + unsigned height = 240 << interlace; + unsigned pitch = 1024 >> interlace; + + //skip first line; as it is always blank (by SNES design) + if(overscan == false) data += 1 * 1024; // 8 + 224 + 8 + if(overscan == true ) data += 9 * 1024; // 0 + 240 + 0 + + for(unsigned y = 0; y < height; y++) { + const uint32_t *sp = data + y * pitch; + uint32_t *dp = output + y * 512; + for(unsigned x = 0; x < width; x++) { + *dp++ = SNES::video.palette[*sp++]; + } + } + + if(config->video.maskOverscan) { + unsigned osw = config->video.maskOverscanHorizontal << hires; + unsigned osh = config->video.maskOverscanVertical << interlace; + + for(unsigned y = 0; y < height; y++) { + uint32_t *dp = output + y * 512; + if(y < osh || y >= height - osh) { + memset(dp, 0, width * sizeof(uint32_t)); + } else { + memset(dp + 0, 0, osw * sizeof(uint32_t)); + memset(dp + width - osw, 0, osw * sizeof(uint32_t)); + } + } + } + + interface->videoRefresh(output, 512 * sizeof(uint32_t), width, height); +} + +void InterfaceSNES::audioSample(int16_t lsample, int16_t rsample) { + signed samples[] = { lsample, rsample }; + dspaudio.sample(samples); + while(dspaudio.pending()) { + dspaudio.read(samples); + audio.sample(samples[0], samples[1]); + } +} + +int16_t InterfaceSNES::inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) { + if(port == 0) { + if(device == SNES::Input::Device::Joypad) return inputManager->snes.port1.gamepad.poll(id); + if(device == SNES::Input::Device::Multitap) { + if(index == 0) return inputManager->snes.port1.multitap1.poll(id); + if(index == 1) return inputManager->snes.port1.multitap1.poll(id); + if(index == 2) return inputManager->snes.port1.multitap1.poll(id); + if(index == 3) return inputManager->snes.port1.multitap1.poll(id); + } + if(device == SNES::Input::Device::Mouse) return inputManager->snes.port1.mouse.poll(id); + } + + if(port == 1) { + if(device == SNES::Input::Device::Joypad) return inputManager->snes.port2.gamepad.poll(id); + if(device == SNES::Input::Device::Multitap) { + if(index == 0) return inputManager->snes.port2.multitap1.poll(id); + if(index == 1) return inputManager->snes.port2.multitap1.poll(id); + if(index == 2) return inputManager->snes.port2.multitap1.poll(id); + if(index == 3) return inputManager->snes.port2.multitap1.poll(id); + } + if(device == SNES::Input::Device::Mouse) return inputManager->snes.port2.mouse.poll(id); + if(device == SNES::Input::Device::SuperScope) return inputManager->snes.port2.superScope.poll(id); + if(device == SNES::Input::Device::Justifier) return inputManager->snes.port2.justifier1.poll(id); + if(device == SNES::Input::Device::Justifiers) { + if(index == 0) return inputManager->snes.port2.justifier1.poll(id); + if(index == 1) return inputManager->snes.port2.justifier2.poll(id); + } + } + + return 0; +} + +string InterfaceSNES::path(SNES::Cartridge::Slot slot, const string &hint) { + static unsigned index[] = { 0, 0, 0, 1, 2, 1 }; + return { interface->slotName[index[(unsigned)slot]], hint }; +} + +void InterfaceSNES::message(const string &text) { + MessageWindow::information(*mainWindow, text); +} diff --git a/ui/interface/snes/snes.hpp b/ui/interface/snes/snes.hpp new file mode 100755 index 00000000..16ec5eec --- /dev/null +++ b/ui/interface/snes/snes.hpp @@ -0,0 +1,32 @@ +struct InterfaceSNES : InterfaceCore, SNES::Interface { + void initialize(); + + void setController(bool port, unsigned device); + + bool cartridgeLoaded(); + bool loadCartridge(const string &filename); + bool loadSatellaviewSlottedCartridge(const string &basename, const string &slotname); + bool loadSatellaviewCartridge(const string &basename, const string &slotname); + bool loadSufamiTurboCartridge(const string &basename, const string &slotAname, const string &slotBname); + bool loadSuperGameBoyCartridge(const string &basename, const string &slotname); + void unloadCartridge(); + + void power(); + void reset(); + void run(); + + void loadMemory(); + void saveMemory(); + + serializer serialize(); + bool unserialize(serializer&); + + void setCheats(const lstring &list = lstring{}); + + void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan); + void audioSample(int16_t lsample, int16_t rsample); + int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id); + + string path(SNES::Cartridge::Slot slot, const string &hint); + void message(const string &text); +}; diff --git a/ui/main.cpp b/ui/main.cpp new file mode 100755 index 00000000..9c5cddea --- /dev/null +++ b/ui/main.cpp @@ -0,0 +1,145 @@ +#include "base.hpp" + +Application *application = 0; +nall::DSP dspaudio; + +//allow files to exist in the same folder as binary; +//otherwise default to home folder +string Application::path(const string &filename) { + string result = { basepath, filename }; + if(file::exists(result)) return result; + return { userpath, filename }; +} + +void Application::run() { + inputManager->scan(); + + autopause = (mainWindow->focused() == false && config->input.focusPolicy == 2); + utility->updateStatus(); + + if(interface->cartridgeLoaded() == false || pause || autopause) { + audio.clear(); + usleep(20 * 1000); + return; + } + + interface->run(); +} + +Application::Application(int argc, char **argv) { + title = "bsnes v084"; + + application = this; + quit = false; + pause = false; + autopause = false; + { + char path[PATH_MAX]; + auto unused = ::realpath(argv[0], path); + basepath = dir(path); + unused = ::userpath(path); + userpath = path; + if(Intrinsics::platform() == Intrinsics::Platform::Windows) { + userpath.append("bsnes/"); + } else { + userpath.append(".config/bsnes/"); + } + mkdir(userpath, 0755); + } + config = new Config; + interface = new Interface; + inputManager = new InputManager; + utility = new Utility; + + string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, "; + normalFont = { fontFamily, "8" }; + boldFont = { fontFamily, "8, Bold" }; + titleFont = { fontFamily, "16, Bold" }; + + compositionEnable = compositor::enabled(); + if(config->video.compositionMode == 2) compositor::enable(false); + + windowManager = new WindowManager; + mainWindow = new MainWindow; + fileBrowser = new FileBrowser; + slotLoader = new SlotLoader; + dipSwitches = new DipSwitches; + settingsWindow = new SettingsWindow; + cheatDatabase = new CheatDatabase; + cheatEditor = new CheatEditor; + stateManager = new StateManager; + windowManager->loadGeometry(); + + utility->setMode(Interface::Mode::None); + mainWindow->setVisible(); + + video.driver(config->video.driver); + video.set(Video::Handle, mainWindow->viewport.handle()); + video.set(Video::Synchronize, config->video.synchronize); + if(video.init() == false) { + MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->video.driver, " video driver." }); + video.driver("None"); + video.init(); + } + utility->bindVideoFilter(); + utility->bindVideoShader(); + + audio.driver(config->audio.driver); + audio.set(Audio::Handle, mainWindow->viewport.handle()); + audio.set(Audio::Synchronize, config->audio.synchronize); + audio.set(Audio::Latency, config->audio.latency); + audio.set(Audio::Frequency, config->audio.frequency); + if(audio.init() == false) { + MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->audio.driver, " audio driver." }); + audio.driver("None"); + audio.init(); + } + + dspaudio.setPrecision(16); + dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0); + dspaudio.setBalance(0.0); + dspaudio.setResampler(DSP::ResampleEngine::Sinc); + dspaudio.setResamplerFrequency(config->audio.frequency); + + input.driver(config->input.driver); + input.set(Input::Handle, mainWindow->viewport.handle()); + if(input.init() == false) { + MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->input.driver, " input driver." }); + input.driver("None"); + input.init(); + } + + if(config->video.startFullScreen) utility->toggleFullScreen(); + if(argc == 2) interface->loadCartridge(argv[1]); + + while(quit == false) { + OS::processEvents(); + Application::run(); + } + + interface->unloadCartridge(); + windowManager->saveGeometry(); + if(compositionEnable) compositor::enable(true); +} + +Application::~Application() { + delete stateManager; + delete cheatEditor; + delete cheatDatabase; + delete settingsWindow; + delete dipSwitches; + delete slotLoader; + delete fileBrowser; + delete mainWindow; + delete windowManager; + delete utility; + delete inputManager; + delete interface; + delete config; +} + +int main(int argc, char **argv) { + new Application(argc, argv); + delete application; + return 0; +} diff --git a/ui/resource.rc b/ui/resource.rc new file mode 100755 index 00000000..7fc5b0e3 --- /dev/null +++ b/ui/resource.rc @@ -0,0 +1,2 @@ +1 24 "../data/bsnes.Manifest" +2 ICON DISCARDABLE "../data/bsnes.ico" diff --git a/ui/settings/advanced.cpp b/ui/settings/advanced.cpp new file mode 100755 index 00000000..c8608d19 --- /dev/null +++ b/ui/settings/advanced.cpp @@ -0,0 +1,82 @@ +AdvancedSettings *advancedSettings = 0; + +AdvancedSettings::AdvancedSettings() { + title.setFont(application->titleFont); + title.setText("Advanced Settings"); + driverLabel.setFont(application->boldFont); + driverLabel.setText("Driver selection: (changes require restart to take effect)"); + videoLabel.setText("Video:"); + audioLabel.setText("Audio:"); + inputLabel.setText("Input:"); + focusPolicyLabel.setFont(application->boldFont); + focusPolicyLabel.setText("When emulation window does not have focus:"); + focusPolicy[0].setText("Allow input"); + focusPolicy[1].setText("Ignore input"); + focusPolicy[2].setText("Pause emulation"); + RadioBox::group(focusPolicy[0], focusPolicy[1], focusPolicy[2]); + focusPolicy[config->input.focusPolicy].setChecked(); + aboutLabel.setFont(application->boldFont); + aboutLabel.setText("bsnes author: byuu license: GPLv3 website: byuu.org"); + + lstring list; + + list.split(";", video.driver_list()); + for(unsigned n = 0; n < list.size(); n++) { + videoDriver.append(list[n]); + if(list[n] == config->video.driver) videoDriver.setSelection(n); + if(list[n] == video.default_driver() && config->video.driver == "") videoDriver.setSelection(n); + } + + list.split(";", audio.driver_list()); + for(unsigned n = 0; n < list.size(); n++) { + audioDriver.append(list[n]); + if(list[n] == config->audio.driver) audioDriver.setSelection(n); + if(list[n] == audio.default_driver() && config->audio.driver == "") audioDriver.setSelection(n); + } + + list.split(";", input.driver_list()); + for(unsigned n = 0; n < list.size(); n++) { + inputDriver.append(list[n]); + if(list[n] == config->input.driver) inputDriver.setSelection(n); + if(list[n] == input.default_driver() && config->input.driver == "") inputDriver.setSelection(n); + } + + append(title, { ~0, 0 }, 5); + append(driverLabel, { ~0, 0 }, 0); + append(driverLayout, { ~0, 0 }, 5); + driverLayout.append(videoLabel, { 0, 0 }, 5); + driverLayout.append(videoDriver, { ~0, 0 }, 5); + driverLayout.append(audioLabel, { 0, 0 }, 5); + driverLayout.append(audioDriver, { ~0, 0 }, 5); + driverLayout.append(inputLabel, { 0, 0 }, 5); + driverLayout.append(inputDriver, { ~0, 0 }, 0); + append(focusPolicyLabel, { ~0, 0 }, 0); + append(focusPolicyLayout, { ~0, 0 }, 5); + focusPolicyLayout.append(focusPolicy[0], { ~0, 0 }, 5); + focusPolicyLayout.append(focusPolicy[1], { ~0, 0 }, 5); + focusPolicyLayout.append(focusPolicy[2], { ~0, 0 }, 0); + append(spacer, { ~0, ~0 }, 0); + append(aboutLabel, { ~0, 0 }, 0); + + videoDriver.onChange = [&] { + lstring list; + list.split(";", video.driver_list()); + config->video.driver = list[videoDriver.selection()]; + }; + + audioDriver.onChange = [&] { + lstring list; + list.split(";", audio.driver_list()); + config->audio.driver = list[audioDriver.selection()]; + }; + + inputDriver.onChange = [&] { + lstring list; + list.split(";", input.driver_list()); + config->input.driver = list[inputDriver.selection()]; + }; + + focusPolicy[0].onTick = [&] { config->input.focusPolicy = 0; }; + focusPolicy[1].onTick = [&] { config->input.focusPolicy = 1; }; + focusPolicy[2].onTick = [&] { config->input.focusPolicy = 2; }; +} diff --git a/ui/settings/advanced.hpp b/ui/settings/advanced.hpp new file mode 100755 index 00000000..89e0432e --- /dev/null +++ b/ui/settings/advanced.hpp @@ -0,0 +1,20 @@ +struct AdvancedSettings : SettingsLayout { + Label title; + Label driverLabel; + HorizontalLayout driverLayout; + Label videoLabel; + ComboBox videoDriver; + Label audioLabel; + ComboBox audioDriver; + Label inputLabel; + ComboBox inputDriver; + Label focusPolicyLabel; + HorizontalLayout focusPolicyLayout; + RadioBox focusPolicy[3]; + Widget spacer; + Label aboutLabel; + + AdvancedSettings(); +}; + +extern AdvancedSettings *advancedSettings; diff --git a/ui/settings/audio.cpp b/ui/settings/audio.cpp new file mode 100755 index 00000000..2f7bd6ed --- /dev/null +++ b/ui/settings/audio.cpp @@ -0,0 +1,151 @@ +AudioSettings *audioSettings = 0; + +AudioSlider::AudioSlider() { + append(name, { 75, 0 }); + append(value, { 75, 0 }); + append(slider, { ~0, 0 }); +} + +unsigned AudioSlider::position() { + unsigned value = slider.position(), center = slider.length() >> 1; + if(value > center) return base + (value - center) * step; + if(value < center) return base - (center - value) * step; + return base; +} + +void AudioSlider::setPosition(unsigned position) { + signed value = position - base, center = slider.length() >> 1; + if(value < 0) return slider.setPosition(center - (abs(value) / step)); + if(value > 0) return slider.setPosition((abs(value) / step) + center); + return slider.setPosition(center); +} + +AudioSettings::AudioSettings() { + title.setFont(application->titleFont); + title.setText("Audio Settings"); + + outputLabel.setFont(application->boldFont); + outputLabel.setText("Output settings:"); + + frequencyLabel.setText("Frequency:"); + frequencySelection.append("32000hz"); + frequencySelection.append("44100hz"); + frequencySelection.append("48000hz"); + frequencySelection.append("96000hz"); + + latencyLabel.setText("Latency:"); + latencySelection.append( "40ms"); + latencySelection.append( "60ms"); + latencySelection.append( "80ms"); + latencySelection.append("100ms"); + latencySelection.append("120ms"); + + resamplerLabel.setText("Resampler:"); + resamplerSelection.append("Linear"); + resamplerSelection.append("Hermite"); + resamplerSelection.append("Sinc"); + + volume.name.setText("Volume:"); + volume.slider.setLength(201); + volume.base = 100; + volume.step = 1; + + frequencyAdjustmentLabel.setFont(application->boldFont); + frequencyAdjustmentLabel.setText("Frequency: (lower to reduce audio crackling; raise to reduce video tearing)"); + + nes.name.setText("NES:"); + nes.slider.setLength(2001); + nes.base = 1789772; + nes.step = 56; + + snes.name.setText("SNES:"); + snes.slider.setLength(2001); + snes.base = 32000; + snes.step = 1; + + gameBoy.name.setText("Game Boy:"); + gameBoy.slider.setLength(2001); + gameBoy.base = 4194304; + gameBoy.step = 131; + + append(title, { ~0, 0 }, 5); + append(outputLabel, { ~0, 0 }, 0); + append(outputLayout, { ~0, 0 }, 5); + outputLayout.append(frequencyLabel, { 0, 0 }, 5); + outputLayout.append(frequencySelection, { ~0, 0 }, 5); + outputLayout.append(latencyLabel, { 0, 0 }, 5); + outputLayout.append(latencySelection, { ~0, 0 }, 5); + outputLayout.append(resamplerLabel, { 0, 0 }, 5); + outputLayout.append(resamplerSelection, { ~0, 0 }, 0); + append(volume, { ~0, 0 }, 5); + append(frequencyAdjustmentLabel, { ~0, 0 }, 0); + append(nes, { ~0, 0 }, 0); + append(snes, { ~0, 0 }, 0); + append(gameBoy, { ~0, 0 }, 0); + + frequencySelection.setSelection( + config->audio.frequency == 32000 ? 0 : + config->audio.frequency == 44100 ? 1 : + config->audio.frequency == 48000 ? 2 : + config->audio.frequency == 96000 ? 3 : 0 + ); + + latencySelection.setSelection( + config->audio.latency == 40 ? 0 : + config->audio.latency == 60 ? 1 : + config->audio.latency == 80 ? 2 : + config->audio.latency == 100 ? 3 : + config->audio.latency == 120 ? 4 : 0 + ); + + resamplerSelection.setSelection( + config->audio.resampler == "linear" ? 0 : + config->audio.resampler == "hermite" ? 1 : + config->audio.resampler == "sinc" ? 2 : 0 + ); + + volume.setPosition(config->audio.volume); + + nes.setPosition(config->audio.frequencyNES); + snes.setPosition(config->audio.frequencySNES); + gameBoy.setPosition(config->audio.frequencyGameBoy); + + frequencySelection.onChange = latencySelection.onChange = resamplerSelection.onChange = + volume.slider.onChange = nes.slider.onChange = snes.slider.onChange = gameBoy.slider.onChange = + { &AudioSettings::synchronize, this }; + + synchronize(); +} + +void AudioSettings::synchronize() { + config->audio.frequency = + frequencySelection.selection() == 0 ? 32000 : + frequencySelection.selection() == 1 ? 44100 : + frequencySelection.selection() == 2 ? 48000 : + frequencySelection.selection() == 3 ? 96000 : 48000; + + config->audio.latency = + latencySelection.selection() == 0 ? 40 : + latencySelection.selection() == 1 ? 60 : + latencySelection.selection() == 2 ? 80 : + latencySelection.selection() == 3 ? 100 : + latencySelection.selection() == 4 ? 120 : 60; + + config->audio.resampler = + resamplerSelection.selection() == 0 ? "linear" : + resamplerSelection.selection() == 1 ? "hermite" : + resamplerSelection.selection() == 2 ? "sinc" : "sinc"; + + config->audio.volume = volume.position(); + + config->audio.frequencyNES = nes.position(); + config->audio.frequencySNES = snes.position(); + config->audio.frequencyGameBoy = gameBoy.position(); + + nes.value.setText({ nes.position(), "hz" }); + snes.value.setText({ snes.position(), "hz" }); + gameBoy.value.setText({ gameBoy.position(), "hz" }); + volume.value.setText({ volume.position(), "%" }); + + interface->updateDSP(); +} diff --git a/ui/settings/audio.hpp b/ui/settings/audio.hpp new file mode 100755 index 00000000..a647d122 --- /dev/null +++ b/ui/settings/audio.hpp @@ -0,0 +1,34 @@ +struct AudioSlider : HorizontalLayout { + Label name; + Label value; + HorizontalSlider slider; + + unsigned base; + unsigned step; + + unsigned position(); + void setPosition(unsigned position); + AudioSlider(); +}; + +struct AudioSettings : SettingsLayout { + Label title; + Label outputLabel; + HorizontalLayout outputLayout; + Label frequencyLabel; + ComboBox frequencySelection; + Label latencyLabel; + ComboBox latencySelection; + Label resamplerLabel; + ComboBox resamplerSelection; + AudioSlider volume; + Label frequencyAdjustmentLabel; + AudioSlider nes; + AudioSlider snes; + AudioSlider gameBoy; + + void synchronize(); + AudioSettings(); +}; + +extern AudioSettings *audioSettings; diff --git a/ui/settings/input.cpp b/ui/settings/input.cpp new file mode 100755 index 00000000..c5be3c62 --- /dev/null +++ b/ui/settings/input.cpp @@ -0,0 +1,150 @@ +InputSettings *inputSettings = 0; + +InputSettings::InputSettings() : activeInput(0) { + title.setFont(application->titleFont); + title.setText("Input Settings"); + inputList.setHeaderText("Name", "Mapping"); + inputList.setHeaderVisible(); + assignPrimary.setVisible(false); + assignSecondary.setVisible(false); + assignTertiary.setVisible(false); + clearButton.setText("Clear"); + + for(unsigned n = 0; n < inputManager->inputList.size(); n++) { + primary.append(inputManager->inputList[n].name); + } + primaryChange(); + + append(title, { ~0, 0 }, 5); + append(selectionLayout, { ~0, 0 }, 5); + selectionLayout.append(primary, { ~0, 0 }, 5); + selectionLayout.append(secondary, { ~0, 0 }, 5); + selectionLayout.append(tertiary, { ~0, 0 }, 0); + append(inputList, { ~0, ~0 }, 5); + append(controlLayout, { ~0, 0 }, 0); + controlLayout.append(assignPrimary, { 100, 0 }, 5); + controlLayout.append(assignSecondary, { 100, 0 }, 5); + controlLayout.append(assignTertiary, { 100, 0 }, 5); + controlLayout.append(spacer, { ~0, 0 }, 0); + controlLayout.append(clearButton, { 80, 0 }, 0); + + primary.onChange = { &InputSettings::primaryChange, this }; + secondary.onChange = { &InputSettings::secondaryChange, this }; + tertiary.onChange = { &InputSettings::tertiaryChange, this }; + inputList.onChange = { &InputSettings::synchronize, this }; + inputList.onActivate = { &InputSettings::assignInput, this }; + assignPrimary.onTick = [&] { assignMouseInput(0); }; + assignSecondary.onTick = [&] { assignMouseInput(1); }; + assignTertiary.onTick = [&] { assignMouseInput(2); }; + clearButton.onTick = { &InputSettings::clearInput, this }; + + synchronize(); +} + +void InputSettings::synchronize() { + PrimaryInput &pinput = inputManager->inputList[primary.selection()]; + SecondaryInput &sinput = pinput[secondary.selection()]; + TertiaryInput &tinput = sinput[tertiary.selection()]; + secondary.setEnabled(pinput.size() > 1); + tertiary.setEnabled(sinput.size() > 1); + clearButton.setEnabled(inputList.selected()); +} + +void InputSettings::primaryChange() { + secondary.reset(); + tertiary.reset(); + PrimaryInput &input = inputManager->inputList[primary.selection()]; + for(unsigned n = 0; n < input.size(); n++) { + secondary.append(input[n].name); + } + secondaryChange(); +} + +void InputSettings::secondaryChange() { + tertiary.reset(); + PrimaryInput &pinput = inputManager->inputList[primary.selection()]; + SecondaryInput &input = pinput[secondary.selection()]; + for(unsigned n = 0; n < input.size(); n++) { + tertiary.append(input[n].name); + } + tertiaryChange(); +} + +void InputSettings::tertiaryChange() { + inputList.reset(); + PrimaryInput &pinput = inputManager->inputList[primary.selection()]; + SecondaryInput &sinput = pinput[secondary.selection()]; + TertiaryInput &input = sinput[tertiary.selection()]; + for(unsigned n = 0; n < input.size(); n++) { + inputList.append(input[n].name, input[n].mapping); + } + synchronize(); + inputList.autoSizeColumns(); +} + +void InputSettings::assignInput() { + PrimaryInput &pinput = inputManager->inputList[primary.selection()]; + SecondaryInput &sinput = pinput[secondary.selection()]; + TertiaryInput &tinput = sinput[tertiary.selection()]; + activeInput = &tinput[inputList.selection()]; + + settingsWindow->setStatusText({ "Set asssignment for [", tinput.name, "::", activeInput->name, "] ..." }); + settingsWindow->panelList.setEnabled(false); + primary.setEnabled(false); + secondary.setEnabled(false); + tertiary.setEnabled(false); + inputList.setEnabled(false); + + if(dynamic_cast(activeInput)) { + assignPrimary.setText("Mouse X-axis"); + assignSecondary.setText("Mouse Y-axis"); + assignPrimary.setVisible(true); + assignSecondary.setVisible(true); + } + + if(dynamic_cast(activeInput)) { + assignPrimary.setText("Mouse Left"); + assignSecondary.setText("Mouse Middle"); + assignTertiary.setText("Mouse Right"); + assignPrimary.setVisible(true); + assignSecondary.setVisible(true); + assignTertiary.setVisible(true); + } +} + +void InputSettings::assignMouseInput(unsigned n) { + if(activeInput == 0) return; + + if(dynamic_cast(activeInput)) { + return inputEvent(mouse(0).axis(n), 1u, true); + } + + if(dynamic_cast(activeInput)) { + return inputEvent(mouse(0).button(n), 1u, true); + } +} + +void InputSettings::clearInput() { + PrimaryInput &pinput = inputManager->inputList[primary.selection()]; + SecondaryInput &sinput = pinput[secondary.selection()]; + TertiaryInput &tinput = sinput[tertiary.selection()]; + activeInput = &tinput[inputList.selection()]; + inputEvent(Scancode::None, 1u); +} + +void InputSettings::inputEvent(int16_t scancode, int16_t value, bool allowMouseInput) { + if(activeInput == 0) return; + if(allowMouseInput == false && (Mouse::isAnyButton(scancode) || Mouse::isAnyAxis(scancode))) return; + if(activeInput->bind(scancode, value) == false) return; + + activeInput = 0; + tertiaryChange(); + settingsWindow->setStatusText(""); + settingsWindow->panelList.setEnabled(true); + primary.setEnabled(true); + inputList.setEnabled(true); + assignPrimary.setVisible(false); + assignSecondary.setVisible(false); + assignTertiary.setVisible(false); + synchronize(); +} diff --git a/ui/settings/input.hpp b/ui/settings/input.hpp new file mode 100755 index 00000000..34d8c11f --- /dev/null +++ b/ui/settings/input.hpp @@ -0,0 +1,30 @@ +struct InputSettings : SettingsLayout { + Label title; + HorizontalLayout selectionLayout; + ComboBox primary; + ComboBox secondary; + ComboBox tertiary; + ListView inputList; + HorizontalLayout controlLayout; + Button assignPrimary; + Button assignSecondary; + Button assignTertiary; + Widget spacer; + Button clearButton; + + InputSettings(); + + void synchronize(); + void primaryChange(); + void secondaryChange(); + void tertiaryChange(); + void assignInput(); + void assignMouseInput(unsigned); + void clearInput(); + void inputEvent(int16_t scancode, int16_t value, bool allowMouseInput = false); + +private: + AbstractInput *activeInput; +}; + +extern InputSettings *inputSettings; diff --git a/ui/settings/settings.cpp b/ui/settings/settings.cpp new file mode 100755 index 00000000..96a6fdd5 --- /dev/null +++ b/ui/settings/settings.cpp @@ -0,0 +1,67 @@ +#include "../base.hpp" +#include "video.cpp" +#include "audio.cpp" +#include "input.cpp" +#include "advanced.cpp" +SettingsWindow *settingsWindow = 0; + +void SettingsLayout::append(Sizable &sizable, const Size &size, unsigned spacing) { + layout.append(sizable, size, spacing); +} + +SettingsLayout::SettingsLayout() { + setMargin(5); + HorizontalLayout::append(spacer, { 120, ~0 }, 5); + HorizontalLayout::append(layout, { ~0, ~0 }, 0); +} + +SettingsWindow::SettingsWindow() { + setTitle("Configuration Settings"); + setGeometry({ 128, 128, 640, 360 }); + setStatusVisible(); + windowManager->append(this, "SettingsWindow"); + + layout.setMargin(5); + panelList.setFont(application->boldFont); + panelList.append("Video"); + panelList.append("Audio"); + panelList.append("Input"); + panelList.append("Advanced"); + + videoSettings = new VideoSettings; + audioSettings = new AudioSettings; + inputSettings = new InputSettings; + advancedSettings = new AdvancedSettings; + + append(layout); + layout.append(panelList, { 120, ~0 }, 5); + append(*videoSettings); + append(*audioSettings); + append(*inputSettings); + append(*advancedSettings); + + panelList.onChange = { &SettingsWindow::panelChanged, this }; + panelList.setSelection(2); + panelChanged(); +} + +SettingsWindow::~SettingsWindow() { + delete advancedSettings; + delete inputSettings; + delete audioSettings; + delete videoSettings; +} + +void SettingsWindow::panelChanged() { + videoSettings->setVisible(false); + audioSettings->setVisible(false); + inputSettings->setVisible(false); + advancedSettings->setVisible(false); + + if(panelList.selected()) switch(panelList.selection()) { + case 0: return videoSettings->setVisible(); + case 1: return audioSettings->setVisible(); + case 2: return inputSettings->setVisible(); + case 3: return advancedSettings->setVisible(); + } +} diff --git a/ui/settings/settings.hpp b/ui/settings/settings.hpp new file mode 100755 index 00000000..eee9cc14 --- /dev/null +++ b/ui/settings/settings.hpp @@ -0,0 +1,24 @@ +struct SettingsLayout : HorizontalLayout { + Widget spacer; + VerticalLayout layout; + + void append(Sizable &widget, const Size &size, unsigned spacing = 0); + SettingsLayout(); +}; + +#include "video.hpp" +#include "audio.hpp" +#include "input.hpp" +#include "advanced.hpp" + +struct SettingsWindow : Window { + HorizontalLayout layout; + ListView panelList; + + void panelChanged(); + + SettingsWindow(); + ~SettingsWindow(); +}; + +extern SettingsWindow *settingsWindow; diff --git a/ui/settings/video.cpp b/ui/settings/video.cpp new file mode 100755 index 00000000..9c829787 --- /dev/null +++ b/ui/settings/video.cpp @@ -0,0 +1,107 @@ +VideoSettings *videoSettings = 0; + +VideoSlider::VideoSlider() { + append(name, { 75, 0 }); + append(value, { 75, 0 }); + append(slider, { ~0, 0 }); +} + +VideoSettings::VideoSettings() { + title.setFont(application->titleFont); + title.setText("Video Settings"); + colorAdjustment.setFont(application->boldFont); + colorAdjustment.setText("Color adjustment:"); + brightness.name.setText("Brightness:"); + brightness.slider.setLength(201); + contrast.name.setText("Contrast:"); + contrast.slider.setLength(201); + gamma.name.setText("Gamma:"); + gamma.slider.setLength(101); + overscanAdjustment.setFont(application->boldFont); + overscanAdjustment.setText("Overscan mask:"); + overscanHorizontal.name.setText("Horizontal:"); + overscanHorizontal.slider.setLength(17); + overscanVertical.name.setText("Vertical:"); + overscanVertical.slider.setLength(17); + fullScreenMode.setFont(application->boldFont); + fullScreenMode.setText("Fullscreen mode:"); + fullScreen[0].setText("Center"); + fullScreen[1].setText("Scale"); + fullScreen[2].setText("Stretch"); + RadioBox::group(fullScreen[0], fullScreen[1], fullScreen[2]); + compositorLabel.setText("Disable window compositor:"); + compositorLabel.setFont(application->boldFont); + compositor[0].setText("Never"); + compositor[1].setText("Fullscreen"); + compositor[2].setText("Always"); + RadioBox::group(compositor[0], compositor[1], compositor[2]); + + append(title, { ~0, 0 }, 5); + append(colorAdjustment, { ~0, 0 }, 0); + append(brightness, { ~0, 0 }, 0); + append(contrast, { ~0, 0 }, 0); + append(gamma, { ~0, 0 }, 5); + append(overscanAdjustment, { ~0, 0 }, 0); + append(overscanHorizontal, { ~0, 0 }, 0); + append(overscanVertical, { ~0, 0 }, 5); + append(fullScreenMode, { ~0, 0 }, 0); + append(fullScreenLayout, { ~0, 0 }, 5); + fullScreenLayout.append(fullScreen[0], { ~0, 0 }, 5); + fullScreenLayout.append(fullScreen[1], { ~0, 0 }, 5); + fullScreenLayout.append(fullScreen[2], { ~0, 0 }, 0); + append(compositorLabel, { ~0, 0 }, 0); + append(compositorLayout, { ~0, 0 }, 0); + compositorLayout.append(compositor[0], { ~0, 0 }, 5); + compositorLayout.append(compositor[1], { ~0, 0 }, 5); + compositorLayout.append(compositor[2], { ~0, 0 }, 0); + + brightness.slider.setPosition(config->video.brightness); + contrast.slider.setPosition(config->video.contrast); + gamma.slider.setPosition(config->video.gamma); + overscanHorizontal.slider.setPosition(config->video.maskOverscanHorizontal); + overscanVertical.slider.setPosition(config->video.maskOverscanVertical); + fullScreen[config->video.fullScreenMode].setChecked(); + compositor[config->video.compositionMode].setChecked(); + + synchronize(); + + brightness.slider.onChange = contrast.slider.onChange = gamma.slider.onChange = + overscanHorizontal.slider.onChange = overscanVertical.slider.onChange = + { &VideoSettings::synchronize, this }; + + fullScreen[0].onTick = [&] { config->video.fullScreenMode = 0; }; + fullScreen[1].onTick = [&] { config->video.fullScreenMode = 1; }; + fullScreen[2].onTick = [&] { config->video.fullScreenMode = 2; }; + + compositor[0].onTick = [&] { + config->video.compositionMode = 0; + compositor::enable(application->compositionEnable); + }; + + compositor[1].onTick = [&] { + config->video.compositionMode = 1; + compositor::enable(application->compositionEnable && mainWindow->fullScreen() == false); + }; + + compositor[2].onTick = [&] { + config->video.compositionMode = 2; + compositor::enable(false); + }; +} + +void VideoSettings::synchronize() { + config->video.brightness = brightness.slider.position(); + config->video.contrast = contrast.slider.position(); + config->video.gamma = gamma.slider.position(); + config->video.maskOverscanHorizontal = overscanHorizontal.slider.position(); + config->video.maskOverscanVertical = overscanVertical.slider.position(); + + brightness.value.setText({ config->video.brightness, "%" }); + contrast.value.setText({ config->video.contrast, "%" }); + gamma.value.setText({ 100 + config->video.gamma, "%" }); + + overscanHorizontal.value.setText({ config->video.maskOverscanHorizontal, "px" }); + overscanVertical.value.setText({ config->video.maskOverscanVertical, "px" }); + + palette.update(); +} diff --git a/ui/settings/video.hpp b/ui/settings/video.hpp new file mode 100755 index 00000000..ce5866d1 --- /dev/null +++ b/ui/settings/video.hpp @@ -0,0 +1,29 @@ +struct VideoSlider : HorizontalLayout { + Label name; + Label value; + HorizontalSlider slider; + + VideoSlider(); +}; + +struct VideoSettings : SettingsLayout { + Label title; + Label colorAdjustment; + VideoSlider brightness; + VideoSlider contrast; + VideoSlider gamma; + Label overscanAdjustment; + VideoSlider overscanHorizontal; + VideoSlider overscanVertical; + Label fullScreenMode; + HorizontalLayout fullScreenLayout; + RadioBox fullScreen[3]; + Label compositorLabel; + HorizontalLayout compositorLayout; + RadioBox compositor[3]; + + void synchronize(); + VideoSettings(); +}; + +extern VideoSettings *videoSettings; diff --git a/ui/tools/cheat-database.cpp b/ui/tools/cheat-database.cpp new file mode 100755 index 00000000..77706cc2 --- /dev/null +++ b/ui/tools/cheat-database.cpp @@ -0,0 +1,74 @@ +CheatDatabase *cheatDatabase = 0; + +CheatDatabase::CheatDatabase() { + setGeometry({ 128, 128, 640, 400 }); + windowManager->append(this, "CheatDatabase"); + + layout.setMargin(5); + cheatList.setCheckable(); + selectAllButton.setText("Select All"); + unselectAllButton.setText("Unselect All"); + acceptButton.setText("Add Codes"); + + append(layout); + layout.append(cheatList, { ~0, ~0 }, 5); + layout.append(controlLayout, { ~0, 0 }, 0); + controlLayout.append(selectAllButton, { 100, 0 }, 5); + controlLayout.append(unselectAllButton, { 100, 0 }, 0); + controlLayout.append(spacer, { ~0, 0 }, 0); + controlLayout.append(acceptButton, { 80, 0 }, 0); + + selectAllButton.onTick = [&] { + for(unsigned n = 0; n < cheatCode.size(); n++) cheatList.setChecked(n, true); + }; + + unselectAllButton.onTick = [&] { + for(unsigned n = 0; n < cheatCode.size(); n++) cheatList.setChecked(n, false); + }; + + acceptButton.onTick = { &CheatDatabase::addCodes, this }; +} + +void CheatDatabase::findCodes() { + cheatList.reset(); + cheatCode.reset(); + + string data; + data.readfile(application->path("cheats.bml")); + BML::Document document(data); + for(auto &root : document) { + if(root.name != "cartridge") continue; + if(root["sha256"].value != interface->sha256()) continue; + + setTitle(root["title"].value); + for(auto &cheat : root) { + if(cheat.name != "cheat") continue; + if(cheat["description"].exists() == false || cheat["code"].exists() == false) continue; + cheatList.append(cheat["description"].value); + cheatCode.append({ cheat["code"].value, "\t", cheat["description"].value }); + } + + setVisible(); + return; + } + + MessageWindow::information(*cheatEditor, "Sorry, no cheat codes were found for this cartridge."); +} + +void CheatDatabase::addCodes() { + for(unsigned n = 0; n < cheatCode.size(); n++) { + if(cheatList.checked(n)) { + lstring part; + part.split<1>("\t", cheatCode[n]); + if(cheatEditor->addCode(part[0], part[1]) == false) { + MessageWindow::warning(*this, "Ran out of empty slots for cheat codes.\nNot all cheat codes were added."); + break; + } + } + } + + setVisible(false); + cheatEditor->updateUI(); + cheatEditor->updateInterface(); + cheatEditor->synchronize(); +} diff --git a/ui/tools/cheat-database.hpp b/ui/tools/cheat-database.hpp new file mode 100755 index 00000000..7c4a89c4 --- /dev/null +++ b/ui/tools/cheat-database.hpp @@ -0,0 +1,18 @@ +struct CheatDatabase : Window { + VerticalLayout layout; + ListView cheatList; + HorizontalLayout controlLayout; + Button selectAllButton; + Button unselectAllButton; + Widget spacer; + Button acceptButton; + + void findCodes(); + void addCodes(); + CheatDatabase(); + +private: + lstring cheatCode; +}; + +extern CheatDatabase *cheatDatabase; diff --git a/ui/tools/cheat-editor.cpp b/ui/tools/cheat-editor.cpp new file mode 100755 index 00000000..bf616b97 --- /dev/null +++ b/ui/tools/cheat-editor.cpp @@ -0,0 +1,185 @@ +CheatEditor *cheatEditor = 0; + +CheatEditor::CheatEditor() { + setTitle("Cheat Editor"); + setGeometry({ 128, 128, 600, 360 }); + windowManager->append(this, "CheatEditor"); + + cheatList.setHeaderText("Slot", "Code", "Description"); + cheatList.setHeaderVisible(); + cheatList.setCheckable(); + codeLabel.setText("Code(s):"); + descLabel.setText("Description:"); + findButton.setText("Find Codes ..."); + clearAllButton.setText("Clear All"); + clearButton.setText("Clear"); + + append(layout); + layout.setMargin(5); + layout.append(cheatList, { ~0, ~0 }, 5); + layout.append(codeLayout, { ~0, 0 }, 5); + codeLayout.append(codeLabel, { 80, 0 }, 0); + codeLayout.append(codeEdit, { ~0, 0 }, 0); + layout.append(descLayout, { ~0, 0 }, 5); + descLayout.append(descLabel, { 80, 0 }, 0); + descLayout.append(descEdit, { ~0, 0 }, 0); + layout.append(controlLayout, { ~0, 0 }, 0); + controlLayout.append(findButton, { 100, 0 }, 0); + controlLayout.append(spacer, { ~0, 0 }, 0); + controlLayout.append(clearAllButton, { 80, 0 }, 5); + controlLayout.append(clearButton, { 80, 0 }, 0); + + for(unsigned n = 0; n < 128; n++) cheatList.append("", "", ""); + updateUI(); + synchronize(); + + cheatList.onChange = { &CheatEditor::synchronize, this }; + cheatList.onTick = [&](unsigned) { updateInterface(); }; + codeEdit.onChange = { &CheatEditor::updateCode, this }; + descEdit.onChange = { &CheatEditor::updateDesc, this }; + findButton.onTick = { &CheatDatabase::findCodes, cheatDatabase }; + clearAllButton.onTick = { &CheatEditor::clearAll, this }; + clearButton.onTick = { &CheatEditor::clearSelected, this }; +} + +void CheatEditor::synchronize() { + layout.setEnabled(interface->cartridgeLoaded()); + + if(cheatList.selected()) { + unsigned n = cheatList.selection(); + codeEdit.setText(cheatText[n][Code]); + descEdit.setText(cheatText[n][Desc]); + codeEdit.setEnabled(true); + descEdit.setEnabled(true); + clearButton.setEnabled(true); + } else { + codeEdit.setText(""); + codeEdit.setEnabled(false); + descEdit.setText(""); + descEdit.setEnabled(false); + clearButton.setEnabled(false); + } +} + +void CheatEditor::updateUI() { + for(unsigned n = 0; n < 128; n++) { + string code = cheatText[n][Code]; + string description = cheatText[n][Code] == "" && cheatText[n][Desc] == "" ? "(empty)" : cheatText[n][Desc]; + lstring codes; + codes.split("+", code); + cheatList.modify(n, decimal<3>(n + 1), codes.size() == 1 ? code : string{ codes[0], "+..." }, description); + } + cheatList.autoSizeColumns(); +} + +void CheatEditor::updateInterface() { + lstring cheatCodes; + for(unsigned n = 0; n < 128; n++) { + string code = cheatText[n][Code]; + if(cheatList.checked(n) && code != "") cheatCodes.append(code.replace(" ", "")); + } + interface->setCheatCodes(cheatCodes); +} + +void CheatEditor::updateCode() { + unsigned n = cheatList.selection(); + cheatText[n][Code] = codeEdit.text(); + updateUI(), updateInterface(); +} + +void CheatEditor::updateDesc() { + unsigned n = cheatList.selection(); + cheatText[n][Desc] = descEdit.text(); + updateUI(), updateInterface(); +} + +void CheatEditor::clearAll() { + if(MessageWindow::question(*this, "Warning: all cheat codes will be permanently erased!\nAre you sure?") + == MessageWindow::Response::Yes) { + reset(); + } +} + +void CheatEditor::clearSelected() { + unsigned n = cheatList.selection(); + cheatList.setChecked(n, false); + cheatText[n][Code] = ""; + cheatText[n][Desc] = ""; + codeEdit.setText(""); + descEdit.setText(""); + updateUI(), updateInterface(); +} + +void CheatEditor::reset() { + synchronize(); + for(unsigned n = 0; n < 128; n++) { + cheatList.setChecked(n, false); + cheatText[n][Code] = ""; + cheatText[n][Desc] = ""; + } + codeEdit.setText(""); + descEdit.setText(""); + updateUI(), updateInterface(); +} + +bool CheatEditor::load(const string &filename) { + synchronize(); + + string data; + if(data.readfile(filename) == false) return false; + + unsigned n = 0; + BML::Document document(data); + for(auto &cheat : document["cartridge"]) { + if(cheat.name != "cheat") continue; + cheatList.setChecked(n, cheat["enable"].exists()); + cheatText[n][Code] = cheat["code"].value; + cheatText[n][Desc] = cheat["description"].value; + if(++n >= 128) break; + } + + updateUI(), updateInterface(); + return true; +} + +bool CheatEditor::save(const string &filename) { + synchronize(); + + signed lastSave = -1; + for(signed n = 127; n >= 0; n--) { + if(cheatText[n][Code] != "" || cheatText[n][Desc] != "") { + lastSave = n; + break; + } + } + + if(lastSave == -1) { + unlink(filename); + return true; + } + + file fp; + if(fp.open(filename, file::mode::write) == false) return false; + + fp.print("cartridge sha256:", interface->sha256(), "\n"); + for(unsigned n = 0; n <= lastSave; n++) { + fp.print("\tcheat", cheatList.checked(n) ? " enable" : "", "\n"); + fp.print("\t\tdescription:", cheatText[n][Desc], "\n"); + fp.print("\t\tcode:", cheatText[n][Code], "\n"); + } + + fp.close(); + return true; +} + +bool CheatEditor::addCode(const string &code, const string &description) { + for(unsigned n = 0; n < 128; n++) { + if(cheatText[n][Code] == "" && cheatText[n][Desc] == "") { + cheatList.setChecked(n, false); + cheatText[n][Code] = code; + cheatText[n][Desc] = description; + return true; + } + } + return false; +} diff --git a/ui/tools/cheat-editor.hpp b/ui/tools/cheat-editor.hpp new file mode 100755 index 00000000..39334337 --- /dev/null +++ b/ui/tools/cheat-editor.hpp @@ -0,0 +1,36 @@ +struct CheatEditor : Window { + VerticalLayout layout; + ListView cheatList; + HorizontalLayout codeLayout; + Label codeLabel; + LineEdit codeEdit; + HorizontalLayout descLayout; + Label descLabel; + LineEdit descEdit; + HorizontalLayout controlLayout; + Button findButton; + Widget spacer; + Button clearAllButton; + Button clearButton; + + void synchronize(); + void updateUI(); + void updateInterface(); + void updateCode(); + void updateDesc(); + void clearAll(); + void clearSelected(); + + void reset(); + bool load(const string &filename); + bool save(const string &filename); + bool addCode(const string &code, const string &description); + + CheatEditor(); + +private: + enum : unsigned { Code = 0, Desc = 1 }; + string cheatText[128][2]; +}; + +extern CheatEditor *cheatEditor; diff --git a/ui/tools/state-manager.cpp b/ui/tools/state-manager.cpp new file mode 100755 index 00000000..bb8f25df --- /dev/null +++ b/ui/tools/state-manager.cpp @@ -0,0 +1,155 @@ +StateManager *stateManager = 0; + +StateManager::StateManager() { + setTitle("State Manager"); + setGeometry({ 128, 128, 600, 360 }); + windowManager->append(this, "StateManager"); + + stateList.setHeaderText("Slot", "Description"); + stateList.setHeaderVisible(); + descLabel.setText("Description:"); + loadButton.setText("Load"); + saveButton.setText("Save"); + eraseButton.setText("Erase"); + + append(layout); + layout.setMargin(5); + layout.append(stateList, { ~0, ~0 }, 5); + layout.append(descLayout, { ~0, 0 }, 5); + descLayout.append(descLabel, { 0, 0 }, 5); + descLayout.append(descEdit, { ~0, 0 }, 0); + layout.append(controlLayout, { ~0, 0 }, 0); + controlLayout.append(spacer, { ~0, 0 }, 0); + controlLayout.append(loadButton, { 80, 0 }, 5); + controlLayout.append(saveButton, { 80, 0 }, 5); + controlLayout.append(eraseButton, { 80, 0 }, 0); + + for(unsigned n = 0; n < 32; n++) stateList.append(decimal<2>(n + 1), "(empty)"); + stateList.autoSizeColumns(); + + synchronize(); + + stateList.onActivate = { &StateManager::slotLoad, this }; + stateList.onChange = { &StateManager::synchronize, this }; + descEdit.onChange = { &StateManager::slotSaveDescription, this }; + loadButton.onTick = { &StateManager::slotLoad, this }; + saveButton.onTick = { &StateManager::slotSave, this }; + eraseButton.onTick = { &StateManager::slotErase, this }; +} + +void StateManager::synchronize() { + layout.setEnabled(interface->cartridgeLoaded()); + + descEdit.setText(""); + descEdit.setEnabled(false); + controlLayout.setEnabled(stateList.selected()); + if(stateList.selected() == false) return; + + if(slot[stateList.selection()].capacity() > 0) { + descEdit.setText(slotLoadDescription(stateList.selection())); + descEdit.setEnabled(true); + } +} + +void StateManager::refresh() { + for(unsigned n = 0; n < 32; n++) { + stateList.modify(n, decimal<2>(n + 1), slotLoadDescription(n)); + } + stateList.autoSizeColumns(); +} + +void StateManager::reset() { + for(unsigned n = 0; n < 32; n++) slot[n] = serializer(); + synchronize(); + refresh(); +} + +bool StateManager::load(const string &filename, unsigned revision) { + for(unsigned n = 0; n < 32; n++) slot[n] = serializer(); + synchronize(); + + file fp; + if(fp.open(filename, file::mode::read) == false) return false; + + if(fp.readl(4) == 0x31415342) { + if(fp.readl(4) == revision) { //'BSA1' + for(unsigned n = 0; n < 32; n++) { + if(fp.read() == false) continue; + unsigned size = fp.readl(4); + uint8_t *data = new uint8_t[size]; + fp.read(data, size); + slot[n] = serializer(data, size); + delete[] data; + } + } + } + + refresh(); + return true; +} + +bool StateManager::save(const string &filename, unsigned revision) { + bool hasSave = false; + for(unsigned n = 0; n < 32; n++) { + if(slot[n].capacity() > 0) hasSave = true; + } + + if(hasSave == false) { + unlink(filename); + return true; + } + + file fp; + if(fp.open(filename, file::mode::write) == false) return false; + + fp.writel(0x31415342, 4); //'BSA1' + fp.writel(revision, 4); + for(unsigned n = 0; n < 32; n++) { + if(slot[n].capacity() == 0) { + fp.write(false); + } else { + fp.write(true); + fp.writel(slot[n].size(), 4); + fp.write(slot[n].data(), slot[n].size()); + } + } +} + +void StateManager::slotLoad() { + if(stateList.selected() == false) return; + serializer s(slot[stateList.selection()].data(), slot[stateList.selection()].capacity()); + interface->unserialize(s); +} + +void StateManager::slotSave() { + if(stateList.selected()) { + slot[stateList.selection()] = interface->serialize(); + } + refresh(); + synchronize(); + descEdit.setFocused(); +} + +void StateManager::slotErase() { + if(stateList.selected()) { + slot[stateList.selection()] = serializer(); + } + refresh(); + synchronize(); +} + +string StateManager::slotLoadDescription(unsigned n) { + if(slot[n].capacity() == 0) return "(empty)"; + char text[DescriptionLength]; + strlcpy(text, (const char*)slot[n].data() + HeaderLength, DescriptionLength); + return text; +} + +void StateManager::slotSaveDescription() { + if(stateList.selected() == false) return; + string text = descEdit.text(); + if(slot[stateList.selection()].capacity() > 0) { + strlcpy((char*)slot[stateList.selection()].data() + HeaderLength, (const char*)text, DescriptionLength); + } + refresh(); +} diff --git a/ui/tools/state-manager.hpp b/ui/tools/state-manager.hpp new file mode 100755 index 00000000..9d3e7a08 --- /dev/null +++ b/ui/tools/state-manager.hpp @@ -0,0 +1,39 @@ +struct StateManager : Window { + VerticalLayout layout; + ListView stateList; + HorizontalLayout descLayout; + Label descLabel; + LineEdit descEdit; + HorizontalLayout controlLayout; + Widget spacer; + Button loadButton; + Button saveButton; + Button eraseButton; + + void synchronize(); + void refresh(); + + void reset(); + bool load(const string &filename, unsigned revision); + bool save(const string &filename, unsigned revision); + + void slotLoad(); + void slotSave(); + void slotErase(); + + string slotLoadDescription(unsigned n); + void slotSaveDescription(); + + StateManager(); + +private: + enum : unsigned { + //these valus are standardized across all emulated platforms: + //{ uint32 signature, version, checksum; char description[512]; ... } + HeaderLength = 12, + DescriptionLength = 512, + }; + serializer slot[32]; +}; + +extern StateManager *stateManager; diff --git a/ui/tools/tools.cpp b/ui/tools/tools.cpp new file mode 100755 index 00000000..7dcad7cf --- /dev/null +++ b/ui/tools/tools.cpp @@ -0,0 +1,4 @@ +#include "../base.hpp" +#include "cheat-database.cpp" +#include "cheat-editor.cpp" +#include "state-manager.cpp" diff --git a/ui/tools/tools.hpp b/ui/tools/tools.hpp new file mode 100755 index 00000000..d6df0ea7 --- /dev/null +++ b/ui/tools/tools.hpp @@ -0,0 +1,3 @@ +#include "cheat-database.hpp" +#include "cheat-editor.hpp" +#include "state-manager.hpp" diff --git a/ui/utility/utility.cpp b/ui/utility/utility.cpp new file mode 100755 index 00000000..0facf416 --- /dev/null +++ b/ui/utility/utility.cpp @@ -0,0 +1,172 @@ +#include "../base.hpp" +Utility *utility = 0; + +void Utility::setMode(Interface::Mode mode) { + video.clear(); + audio.clear(); + + mainWindow->nesMenu.setVisible(false); + mainWindow->snesMenu.setVisible(false); + mainWindow->gameBoyMenu.setVisible(false); + + if(mode == Interface::Mode::None) { + mainWindow->setTitle(application->title); + mainWindow->setStatusText("No cartridge loaded"); + cheatEditor->reset(); + stateManager->reset(); + } + + else if(mode == Interface::Mode::NES) { + mainWindow->setTitle(notdir(interface->baseName)); + mainWindow->nesMenu.setVisible(true); + dspaudio.setChannels(1); + } + + else if(mode == Interface::Mode::SNES) { + mainWindow->setTitle(notdir(interface->baseName)); + mainWindow->snesMenu.setVisible(true); + dspaudio.setChannels(2); + } + + else if(mode == Interface::Mode::GameBoy) { + mainWindow->gameBoyMenu.setText( + GameBoy::system.cgb() == false ? "Game Boy" : "Game Boy Color" + ); + mainWindow->setTitle(notdir(interface->baseName)); + mainWindow->gameBoyMenu.setVisible(true); + dspaudio.setChannels(2); + } + + interface->updateDSP(); + mainWindow->synchronize(); + resizeMainWindow(); +} + +void Utility::resizeMainWindow(bool shrink) { + Geometry geometry = mainWindow->geometry(); + unsigned width = geometry.width, height = geometry.height; + + switch(interface->mode()) { + case Interface::Mode::None: return mainWindow->viewport.setGeometry({ 0, 0, 1, 1 }); + case Interface::Mode::NES: width = 256, height = 240; break; + case Interface::Mode::SNES: width = 256, height = 240; break; + case Interface::Mode::GameBoy: width = 160, height = 144; break; + } + + if(config->video.correctAspectRatio) { + if(interface->mode() == Interface::Mode::NES + || interface->mode() == Interface::Mode::SNES + ) width = (double)width * 1.226; + } + + unsigned maxW = geometry.width / width; + unsigned maxH = geometry.height / height; + unsigned maxM = max(1u, min(maxW, maxH)); + + width = width * maxM; + height = height * maxM; + + if(mainWindow->fullScreen() == true) { + if(config->video.fullScreenMode == 1) { //scale + width = (double)width * ((double)geometry.height / height); + height = geometry.height; + } + + if(config->video.fullScreenMode == 2) { //stretch + width = geometry.width; + height = geometry.height; + } + } + + if(shrink == false) { + if(geometry.width < width ) width = geometry.width; + if(geometry.height < height) height = geometry.height; + + mainWindow->viewport.setGeometry({ + (geometry.width - width) / 2, (geometry.height - height) / 2, + width, height + }); + } else { + mainWindow->setGeometry({ geometry.x, geometry.y, width, height }); + mainWindow->viewport.setGeometry({ 0, 0, width, height }); + } +} + +void Utility::toggleFullScreen() { + static Geometry geometry; + + if(mainWindow->fullScreen() == false) { + geometry = mainWindow->geometry(); + mainWindow->setMenuVisible(false); + mainWindow->setStatusVisible(false); + mainWindow->setFullScreen(true); + input.acquire(); + } else { + input.unacquire(); + mainWindow->setMenuVisible(true); + mainWindow->setStatusVisible(true); + mainWindow->setFullScreen(false); + mainWindow->setGeometry(geometry); + } + + resizeMainWindow(); + if(application->compositionEnable) { + if(config->video.compositionMode == 1) { + compositor::enable(mainWindow->fullScreen() == false); + } + } +} + +void Utility::bindVideoFilter() { + if(filter.opened()) filter.close(); + if(config->video.filter == "None") return; + if(filter.open_absolute(config->video.filter)) { + filter.dl_size = filter.sym("filter_size"); + filter.dl_render = filter.sym("filter_render"); + if(!filter.dl_size || !filter.dl_render) filter.close(); + } +} + +void Utility::bindVideoShader() { + if(config->video.shader == "None") { + video.set(Video::Shader, (const char*)""); + video.set(Video::Filter, 0u); + } else if(config->video.shader == "Blur") { + video.set(Video::Shader, (const char*)""); + video.set(Video::Filter, 1u); + } else { + string data; + data.readfile(config->video.shader); + video.set(Video::Shader, (const char*)data); + } +} + +void Utility::updateStatus() { + time_t currentTime = time(0); + string text; + if((currentTime - statusTime) <= 2) { + text = statusMessage; + } else if(interface->cartridgeLoaded() == false) { + text = "No cartridge loaded"; + } else if(application->pause || application->autopause) { + text = "Paused"; + } else { + text = statusText; + } + if(text != mainWindow->statusText()) { + mainWindow->setStatusText(text); + } +} + +void Utility::setStatusText(const string &text) { + statusText = text; +} + +void Utility::showMessage(const string &message) { + statusTime = time(0); + statusMessage = message; +} + +Utility::Utility() { + statusTime = 0; +} diff --git a/ui/utility/utility.hpp b/ui/utility/utility.hpp new file mode 100755 index 00000000..50cfc3b5 --- /dev/null +++ b/ui/utility/utility.hpp @@ -0,0 +1,20 @@ +struct Utility { + void setMode(Interface::Mode mode); + void resizeMainWindow(bool shrink = false); + void toggleFullScreen(); + void bindVideoFilter(); + void bindVideoShader(); + + void updateStatus(); + void setStatusText(const string &text); + void showMessage(const string &text); + + Utility(); + +private: + time_t statusTime; + string statusText; + string statusMessage; +}; + +extern Utility *utility; diff --git a/ui/window/window.cpp b/ui/window/window.cpp new file mode 100755 index 00000000..dec01b68 --- /dev/null +++ b/ui/window/window.cpp @@ -0,0 +1,46 @@ +#include "../base.hpp" +WindowManager *windowManager = 0; + +void WindowManager::append(Window *window, const string &name) { + windowList.append({ window, name, geometry(window->geometry()) }); + + window->setMenuFont(application->normalFont); + window->setWidgetFont(application->normalFont); + window->setStatusFont(application->boldFont); +} + +string WindowManager::geometry(const Geometry &geometry) { + return { geometry.x, ",", geometry.y, ",", geometry.width, ",", geometry.height }; +} + +Geometry WindowManager::geometry(const string &geometry) { + lstring part; + part.split(",", geometry); + Geometry geom = { + (signed)integer(part[0]), (signed)integer(part[1]), + (unsigned)decimal(part[2]), (unsigned)decimal(part[3]) + }; + geom.x = max(0, min(7680, geom.x)); + geom.y = max(0, min(4800, geom.y)); + geom.width = min(7680, geom.width ); + geom.height = min(4800, geom.height); + return geom; +} + +void WindowManager::loadGeometry() { + for(auto &window : windowList) { + config.attach(window.geometry, window.name); + } + config.load(application->path("geometry.cfg")); + config.save(application->path("geometry.cfg")); + for(auto &window : windowList) { + window.window->setGeometry(geometry(window.geometry)); + } +} + +void WindowManager::saveGeometry() { + for(auto &window : windowList) { + window.geometry = geometry(window.window->geometry()); + } + config.save(application->path("geometry.cfg")); +} diff --git a/ui/window/window.hpp b/ui/window/window.hpp new file mode 100755 index 00000000..e67ab928 --- /dev/null +++ b/ui/window/window.hpp @@ -0,0 +1,21 @@ +struct WindowManager { + struct WindowList { + Window *window; + string name; + string geometry; + }; + vector windowList; + + void append(Window *window, const string &name); + + string geometry(const Geometry &geometry); + Geometry geometry(const string &geometry); + + void loadGeometry(); + void saveGeometry(); + +private: + configuration config; +}; + +extern WindowManager *windowManager;